From 76fdb7e577e044ffd445e1dc4f2a0bd4b64ecb5a Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 10 Mar 2009 14:03:13 -0700 Subject: [PATCH] Implement OFPP_NORMAL action in secchan and hook into vswitchd. Bonded interface accounting and rebalancing has been removed and needs to be added back in. Handling of ARP packets arriving on bonded interfaces is also known to be broken. --- secchan/ofproto.c | 189 ++++++----- secchan/ofproto.h | 6 + vswitchd/automake.mk | 2 - vswitchd/bridge.c | 724 ++++++------------------------------------- vswitchd/flowtrack.c | 186 ----------- vswitchd/flowtrack.h | 92 ------ 6 files changed, 214 insertions(+), 985 deletions(-) delete mode 100644 vswitchd/flowtrack.c delete mode 100644 vswitchd/flowtrack.h diff --git a/secchan/ofproto.c b/secchan/ofproto.c index 36794ae6..24637d89 100644 --- a/secchan/ofproto.c +++ b/secchan/ofproto.c @@ -62,6 +62,7 @@ #include "shash.h" #include "status.h" #include "svec.h" +#include "tag.h" #include "timeval.h" #include "vconn.h" #include "vconn-ssl.h" @@ -90,7 +91,8 @@ static void hton_ofp_phy_port(struct ofp_phy_port *); static void xlate_actions(const union ofp_action *in, size_t n_in, const flow_t *flow, struct ofproto *ofproto, - struct odp_actions *out); + bool revalidating, + struct odp_actions *out, tag_type *tags); #define UNKNOWN_SUPER ((struct rule *)-1) struct rule { @@ -104,6 +106,7 @@ struct rule { uint64_t byte_count; /* Bytes from *expired* subrules. */ uint8_t tcp_flags; /* Bitwise-OR of all TCP flags seen. */ uint8_t ip_tos; /* Last-seen IP type-of-service. */ + tag_type tags; /* Tags (set only by hooks). */ struct rule *super; struct list list; @@ -116,8 +119,8 @@ struct rule { static void rule_free(struct rule *); static void rule_destroy(struct rule *); static struct rule *rule_from_cls_rule(const struct cls_rule *); -static void rule_make_actions(struct ofproto *, - const struct rule *, struct odp_actions *); +static void rule_make_actions(struct ofproto *, struct rule *, + bool revalidating, struct odp_actions *); struct ofconn { struct list node; @@ -185,8 +188,8 @@ static void send_packet_in_miss(struct ofpbuf *, void *ofproto); static void send_packet_in_action(struct ofpbuf *, void *ofproto); static void update_used(struct ofproto *); static void expire_rule(struct cls_rule *, void *ofproto); -static bool revalidate_subrule(struct ofproto *p, struct rule *subrule); -static void revalidate_subrule_cb(struct cls_rule *sub_, void *p_); +static bool revalidate_rule(struct ofproto *p, struct rule *rule); +static void revalidate_cb(struct cls_rule *rule_, void *p_); static void handle_odp_msg(struct ofproto *, struct ofpbuf *); @@ -615,6 +618,16 @@ ofproto_destroy(struct ofproto *p) int ofproto_run(struct ofproto *p) +{ + int error = ofproto_run1(p); + if (!error) { + error = ofproto_run2(p, false, NULL); + } + return error; +} + +int +ofproto_run1(struct ofproto *p) { struct ofconn *ofconn, *next_ofconn; char *devname; @@ -706,8 +719,32 @@ ofproto_run(struct ofproto *p) classifier_for_each(&p->cls, CLS_INC_EXACT, expire_rule, p); } - if (p->need_revalidate) { - classifier_for_each(&p->cls, CLS_INC_EXACT, revalidate_subrule_cb, p); + return 0; +} + +struct revalidate_cbdata { + struct ofproto *ofproto; + bool revalidate_all; /* Revalidate all exact-match rules? */ + bool revalidate_subrules; /* Revalidate all exact-match subrules? */ + struct tag_set revalidate_set; /* Set of tags to revalidate. */ +}; + +int +ofproto_run2(struct ofproto *p, + bool revalidate_all, const struct tag_set *revalidate_set) +{ + if (p->need_revalidate || revalidate_all + || (revalidate_set && !tag_set_is_empty(revalidate_set))) { + struct revalidate_cbdata cbdata; + cbdata.ofproto = p; + cbdata.revalidate_all = revalidate_all; + cbdata.revalidate_subrules = p->need_revalidate; + if (revalidate_set) { + cbdata.revalidate_set = *revalidate_set; + } else { + tag_set_init(&cbdata.revalidate_set); + } + classifier_for_each(&p->cls, CLS_INC_EXACT, revalidate_cb, &cbdata); p->need_revalidate = false; } @@ -765,7 +802,7 @@ ofproto_send_packet(struct ofproto *p, const flow_t *flow, struct odp_actions odp_actions; int error; - xlate_actions(actions, n_actions, flow, p, &odp_actions); + xlate_actions(actions, n_actions, flow, p, false, &odp_actions, NULL); error = dpif_execute(&p->dpif, flow->in_port, odp_actions.actions, odp_actions.n_actions, packet); odp_actions_free(&odp_actions); @@ -791,6 +828,7 @@ ofproto_add_flow(struct ofproto *p, rule->byte_count = 0; rule->tcp_flags = 0; rule->ip_tos = 0; + rule->tags = 0; rule->super = NULL; /* XXX */ list_init(&rule->list); rule->n_actions = n_actions; @@ -803,7 +841,7 @@ ofproto_add_flow(struct ofproto *p, } if (!wildcards) { - rule_make_actions(p, rule, &odp_actions); + rule_make_actions(p, rule, false, &odp_actions); if (packet) { if (!ofproto_send_packet(p, flow, actions, n_actions, packet)) { rule->byte_count = packet->size; @@ -838,7 +876,8 @@ ofproto_set_actions(struct ofproto *ofproto, const flow_t *flow, rule->n_actions = n_actions; rule->actions = xmemdup(actions, n_actions * sizeof *rule->actions); - rule_make_actions(ofproto, rule, &odp_actions); + rule->tags = 0; + rule_make_actions(ofproto, rule, false, &odp_actions); dpif_flow_set_actions(&ofproto->dpif, flow, odp_actions.actions, odp_actions.n_actions); odp_actions_free(&odp_actions); @@ -1228,13 +1267,14 @@ rule_has_out_port(const struct rule *rule, uint16_t out_port) } static void -rule_make_actions(struct ofproto *p, - const struct rule *rule, struct odp_actions *actions) +rule_make_actions(struct ofproto *p, struct rule *rule, bool revalidating, + struct odp_actions *actions) { const struct rule *super = rule->super ? rule->super : rule; assert(!rule->cr.wc.wildcards); + rule->tags = 0; xlate_actions(super->actions, super->n_actions, &rule->cr.flow, p, - actions); + revalidating, actions, &rule->tags); } static void @@ -1417,20 +1457,21 @@ add_controller_action(struct odp_actions *actions, struct action_xlate_ctx { /* Input. */ - const union ofp_action *in; /* OpenFlow actions. */ - size_t n_in; /* Number of elements in 'in' array. */ const flow_t *flow; /* Flow to which these actions correspond. */ int recurse; /* Recursion level, via xlate_table_action. */ struct ofproto *ofproto; + bool revalidating; /* Output. */ struct odp_actions *out; /* Datapath actions. */ + tag_type *tags; /* Tags associated with OFPP_NORMAL actions. */ }; -static void do_xlate_actions(struct action_xlate_ctx *ctx); +static void do_xlate_actions(const union ofp_action *in, size_t n_in, + struct action_xlate_ctx *ctx); static void -xlate_table_action(const struct action_xlate_ctx *ctx, uint16_t in_port) +xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) { struct ofproto *p = ctx->ofproto; struct action_xlate_ctx nested_ctx; @@ -1449,7 +1490,7 @@ xlate_table_action(const struct action_xlate_ctx *ctx, uint16_t in_port) return; } else if (rule->super && p->need_revalidate) { /* This might be a subrule that is now invalid. Revalidate it. */ - if (!revalidate_subrule(p, rule)) { + if (!revalidate_rule(p, rule)) { /* The subrule got deleted so we can optimize slightly by only * looking through the wildcarded rules. */ rule = rule_from_cls_rule(classifier_lookup_wild(&p->cls, &flow)); @@ -1462,17 +1503,13 @@ xlate_table_action(const struct action_xlate_ctx *ctx, uint16_t in_port) rule = rule->super; } - nested_ctx.in = rule->actions; - nested_ctx.n_in = rule->n_actions; - nested_ctx.flow = ctx->flow; - nested_ctx.recurse = ctx->recurse + 1; - nested_ctx.ofproto = ctx->ofproto; - nested_ctx.out = ctx->out; - do_xlate_actions(&nested_ctx); + ctx->recurse++; + do_xlate_actions(rule->actions, rule->n_actions, &nested_ctx); + ctx->recurse--; } static void -xlate_output_action(const struct action_xlate_ctx *ctx, +xlate_output_action(struct action_xlate_ctx *ctx, const struct ofp_action_output *oao) { uint16_t odp_port; @@ -1485,7 +1522,13 @@ xlate_output_action(const struct action_xlate_ctx *ctx, xlate_table_action(ctx, ctx->flow->in_port); break; case OFPP_NORMAL: - add_output_group_action(ctx->out, DP_GROUP_FLOOD); /* XXX */ + if (ctx->ofproto->ofhooks->normal_cb) { + ctx->ofproto->ofhooks->normal_cb(ctx->flow, ctx->revalidating, + ctx->out, ctx->tags, + ctx->ofproto->aux); + } else { + add_output_group_action(ctx->out, DP_GROUP_FLOOD); + } break; case OFPP_FLOOD: add_output_group_action(ctx->out, DP_GROUP_FLOOD); @@ -1509,7 +1552,7 @@ xlate_output_action(const struct action_xlate_ctx *ctx, } static void -xlate_nicira_action(const struct action_xlate_ctx *ctx, +xlate_nicira_action(struct action_xlate_ctx *ctx, const struct nx_action_header *nah) { const struct nx_action_snat *nas; @@ -1537,14 +1580,13 @@ xlate_nicira_action(const struct action_xlate_ctx *ctx, } static void -do_xlate_actions(struct action_xlate_ctx *ctx) +do_xlate_actions(const union ofp_action *in, size_t n_in, + struct action_xlate_ctx *ctx) { struct actions_iterator iter; const union ofp_action *ia; - for (ia = actions_first(&iter, ctx->in, ctx->n_in); ia; - ia = actions_next(&iter)) - { + for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) { uint16_t type = ntohs(ia->type); union odp_action *oa; @@ -1602,18 +1644,19 @@ do_xlate_actions(struct action_xlate_ctx *ctx) static void xlate_actions(const union ofp_action *in, size_t n_in, - const flow_t *flow, struct ofproto *ofproto, - struct odp_actions *out) + const flow_t *flow, struct ofproto *ofproto, bool revalidating, + struct odp_actions *out, tag_type *tags) { + tag_type no_tags = 0; struct action_xlate_ctx ctx; odp_actions_init(out); - ctx.in = in; - ctx.n_in = n_in; ctx.flow = flow; ctx.recurse = 0; ctx.ofproto = ofproto; + ctx.revalidating = revalidating; ctx.out = out; - do_xlate_actions(&ctx); + ctx.tags = tags ? tags : &no_tags; + do_xlate_actions(in, n_in, &ctx); } static int @@ -1647,7 +1690,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn, flow_extract(&payload, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow); xlate_actions((const union ofp_action *) opo->actions, n_actions, &flow, - p, &actions); + p, false, &actions, NULL); dpif_execute(&p->dpif, flow.in_port, actions.actions, actions.n_actions, &payload); odp_actions_free(&actions); @@ -2120,7 +2163,8 @@ send_buffered(struct ofproto *p, struct ofconn *ofconn, uint32_t buffer_id, } flow_extract(packet, in_port, &flow); - xlate_actions(rule->actions, rule->n_actions, &flow, p, &actions); + xlate_actions(rule->actions, rule->n_actions, &flow, p, false, + &actions, NULL); error = dpif_execute(&p->dpif, in_port, actions.actions, actions.n_actions, packet); if (!error) { @@ -2148,6 +2192,7 @@ add_flow(struct ofproto *p, struct ofconn *ofconn, rule->byte_count = 0; rule->tcp_flags = 0; rule->ip_tos = 0; + rule->tags = 0; rule->super = NULL; list_init(&rule->list); rule->n_actions = n_actions; @@ -2186,7 +2231,7 @@ add_flow(struct ofproto *p, struct ofconn *ofconn, struct odp_actions actions; xlate_actions((const union ofp_action *) ofm->actions, n_actions, - &rule->cr.flow, p, &actions); + &rule->cr.flow, p, false, &actions, NULL); odp_flow.key = rule->cr.flow; odp_flow.actions = actions.actions; @@ -2232,7 +2277,7 @@ modify_flow(struct ofproto *p, const struct ofp_flow_mod *ofm, struct odp_actions actions; xlate_actions((const union ofp_action *) ofm->actions, n_actions, - &rule->cr.flow, p, &actions); + &rule->cr.flow, p, false, &actions, NULL); odp_flow.key = rule->cr.flow; odp_flow.actions = actions.actions; odp_flow.n_actions = actions.n_actions; @@ -2530,6 +2575,7 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) subrule->packet_count = subrule->byte_count = 0; subrule->tcp_flags = 0; subrule->ip_tos = 0; + subrule->tags = 0; subrule->super = rule; subrule->n_actions = 0; subrule->actions = NULL; @@ -2542,7 +2588,7 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) free(subrule); /* Execute old_sr on packet. */ - rule_make_actions(p, old_sr, &actions); + rule_make_actions(p, old_sr, false, &actions); dpif_execute(&p->dpif, msg->port, actions.actions, actions.n_actions, &payload); odp_actions_free(&actions); @@ -2558,17 +2604,16 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) rule->used = time_msec(); /* Install flow entry into datapath. */ - rule_make_actions(p, subrule, &actions); + rule_make_actions(p, subrule, false, &actions); odp_flow.key = flow; odp_flow.actions = actions.actions; odp_flow.n_actions = actions.n_actions; dpif_flow_add(&p->dpif, &odp_flow); } else { - /* XXX This should happen only if a flow got dropped--perhaps a hash - * collision? Oh, it could also indicate that the packet was buffered - * before we processed another packet from the same flow. */ + /* A flow got dropped due to a hash collision, or the packet was + * buffered before we processed another packet from the same flow. */ subrule = rule; - rule_make_actions(p, subrule, &actions); + rule_make_actions(p, subrule, false, &actions); } /* Execute subrule on packet. */ @@ -2579,49 +2624,50 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) } static void -revalidate_subrule_cb(struct cls_rule *sub_, void *p_) +revalidate_cb(struct cls_rule *sub_, void *cbdata_) { struct rule *sub = rule_from_cls_rule(sub_); - struct ofproto *p = p_; + struct revalidate_cbdata *cbdata = cbdata_; - if (sub->super) { - revalidate_subrule(p, sub); + if (cbdata->revalidate_all + || (cbdata->revalidate_subrules && sub->super) + || (tag_set_intersects(&cbdata->revalidate_set, sub->tags))) { + revalidate_rule(cbdata->ofproto, sub); } } static bool -revalidate_subrule(struct ofproto *p, struct rule *sub) +revalidate_rule(struct ofproto *p, struct rule *rule) { - const flow_t *flow = &sub->cr.flow; - struct rule *super; + const flow_t *flow = &rule->cr.flow; + struct odp_actions actions; - super = rule_from_cls_rule(classifier_lookup_wild(&p->cls, flow)); - if (super != sub->super) { + if (rule->super) { + struct rule *super; + super = rule_from_cls_rule(classifier_lookup_wild(&p->cls, flow)); if (!super) { struct odp_flow odp_flow; memset(&odp_flow.stats, 0, sizeof odp_flow.stats); - odp_flow.key = sub->cr.flow; + odp_flow.key = rule->cr.flow; odp_flow.actions = NULL; odp_flow.n_actions = 0; dpif_flow_del(&p->dpif, &odp_flow); - classifier_remove(&p->cls, &sub->cr); - rule_destroy(sub); + classifier_remove(&p->cls, &rule->cr); + rule_destroy(rule); return false; } else { - struct odp_actions actions; - - sub->super = super; - sub->hard_timeout = super->hard_timeout; - sub->idle_timeout = super->idle_timeout; - sub->created = super->created; - sub->used = 0; - - rule_make_actions(p, sub, &actions); - dpif_flow_set_actions(&p->dpif, flow, actions.actions, - actions.n_actions); - odp_actions_free(&actions); + rule->super = super; + rule->hard_timeout = super->hard_timeout; + rule->idle_timeout = super->idle_timeout; + rule->created = super->created; + rule->used = 0; } } + + rule_make_actions(p, rule, true, &actions); + dpif_flow_set_actions(&p->dpif, flow, actions.actions, + actions.n_actions); + odp_actions_free(&actions); return true; } @@ -2771,7 +2817,6 @@ update_used(struct ofproto *p) } update_time(rule, &f->stats); - /* XXX update p->next_expiration */ } free(flows); } diff --git a/secchan/ofproto.h b/secchan/ofproto.h index 8f977a7a..c9a5d8ac 100644 --- a/secchan/ofproto.h +++ b/secchan/ofproto.h @@ -38,6 +38,7 @@ #include #include #include "flow.h" +#include "tag.h" struct odp_actions; struct ofhooks; @@ -58,6 +59,9 @@ int ofproto_create(const char *datapath, const struct ofhooks *, void *aux, struct ofproto **ofprotop); void ofproto_destroy(struct ofproto *); int ofproto_run(struct ofproto *); +int ofproto_run1(struct ofproto *); +int ofproto_run2(struct ofproto *, + bool revalidate_all, const struct tag_set *revalidate_set); void ofproto_wait(struct ofproto *); bool ofproto_is_alive(const struct ofproto *); @@ -111,6 +115,8 @@ struct ofhooks { bool (*packet_in_cb)(const flow_t *, const struct ofpbuf *payload, void *aux); void (*flow_expired_cb)(const struct ofexpired *, void *aux); + void (*normal_cb)(const flow_t *, bool revalidating, + struct odp_actions *, tag_type *, void *aux); }; #endif /* ofproto.h */ diff --git a/vswitchd/automake.mk b/vswitchd/automake.mk index 8885f384..9a52500d 100644 --- a/vswitchd/automake.mk +++ b/vswitchd/automake.mk @@ -8,8 +8,6 @@ vswitchd_vswitchd_SOURCES = \ vswitchd/brcompat.h \ vswitchd/bridge.c \ vswitchd/bridge.h \ - vswitchd/flowtrack.c \ - vswitchd/flowtrack.h \ vswitchd/vswitchd.c vswitchd_vswitchd_LDADD = \ secchan/libsecchan.a \ diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index dc75e868..0ed0a332 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -46,7 +46,6 @@ #include "dirs.h" #include "dpif.h" #include "flow.h" -#include "flowtrack.h" #include "hash.h" #include "list.h" #include "mac-learning.h" @@ -70,6 +69,11 @@ #define THIS_MODULE VLM_bridge #include "vlog.h" +struct dst { + uint16_t vlan; + uint16_t dp_ifidx; +}; + struct iface { struct port *port; /* Containing port. */ size_t port_ifidx; /* Index within containing port. */ @@ -167,7 +171,6 @@ struct bridge { size_t n_ports, allocated_ports; /* Flow tracking. */ - struct ft *ft; struct tag_set revalidate_set; bool flush; @@ -200,11 +203,6 @@ static void bridge_flush(struct bridge *); static void bridge_pick_local_hw_addr(struct bridge *, struct iface *local_iface); -static void revalidate_flow(struct bridge *, struct ft_flow *); - -static void flowstats_run(struct bridge *); -static void flowstats_wait(struct bridge *); - static void bond_run(struct bridge *); static void bond_wait(struct bridge *); @@ -225,8 +223,6 @@ static void brstp_reconfigure(struct bridge *); static void brstp_adjust_timers(struct bridge *); static void brstp_run(struct bridge *); static void brstp_wait(struct bridge *); -static void brstp_receive(struct bridge *, const flow_t *, - const struct ofpbuf *); static void iface_create(struct port *, const char *name); static void iface_destroy(struct iface *); @@ -559,7 +555,6 @@ bridge_wait(void) if (br->ml) { mac_learning_wait(br->ml); } - flowstats_wait(br); bond_wait(br); brstp_wait(br); if (!tag_set_is_empty(&br->revalidate_set)) { @@ -624,7 +619,6 @@ bridge_create(const char *name) port_array_init(&br->ifaces); - br->ft = ft_create(); tag_set_init(&br->revalidate_set); br->flush = false; @@ -653,7 +647,6 @@ bridge_destroy(struct bridge *br) dpif_close(&br->dpif); ofproto_destroy(br->ofproto); free(br->controller); - ft_destroy(br->ft); mac_learning_destroy(br->ml); port_array_destroy(&br->ifaces); free(br->ports); @@ -700,31 +693,18 @@ bridge_run_one(struct bridge *br) { int error; - if (br->controller) { - return ofproto_run(br->ofproto); + error = ofproto_run1(br->ofproto); + if (error) { + return error; } - /* Now do the things that may want to revalidate flows. */ - error = ofproto_run(br->ofproto); - hmap_shrink(&br->ft->flows); if (br->ml) { mac_learning_run(br->ml, &br->revalidate_set); } - flowstats_run(br); bond_run(br); brstp_run(br); - /* Now revalidate any flows that need it. */ - if (br->flush || !tag_set_is_empty(&br->revalidate_set)) { - struct ft_flow *f, *next; - - HMAP_FOR_EACH_SAFE (f, next, struct ft_flow, node, &br->ft->flows) { - if (br->flush - || tag_set_intersects(&br->revalidate_set, f->tags)) { - revalidate_flow(br, f); - } - } - } + error = ofproto_run2(br->ofproto, br->flush, &br->revalidate_set); tag_set_init(&br->revalidate_set); br->flush = false; @@ -890,16 +870,28 @@ bridge_reconfigure_one(struct bridge *br) } else { ofproto_set_remote_execution(br->ofproto, NULL, NULL); } - } else { + if (br->controller) { - /* There was a controller configured, so we want to disconnect - * from it so that connect_ofproto() will set up a "loopback" - * connection to us over a socketpair. */ - ofproto_set_controller(br->ofproto, NULL); - } else { - /* No controller configured before either, so we're already doing - * the right thing. */ + /* Get rid of our match-everything flow, and all the rest while + * we're at it (which should mostly be subflows set up by that + * one). */ + ofproto_flush_flows(br->ofproto); } + } else { + union ofp_action action; + flow_t flow; + + /* Set up a flow that matches every packet and directs them to + * OFPP_NORMAL (which goes to us). */ + memset(&action, 0, sizeof action); + action.type = htons(OFPAT_OUTPUT); + action.output.len = htons(sizeof action); + action.output.port = htons(OFPP_NORMAL); + memset(&flow, 0, sizeof flow); + ofproto_add_flow(br->ofproto, &flow, OFPFW_ALL, 0, + &action, 1, NULL, 0); + + ofproto_set_controller(br->ofproto, NULL); ofproto_set_in_band(br->ofproto, false); ofproto_set_max_backoff(br->ofproto, 1); ofproto_set_probe_interval(br->ofproto, 5); @@ -987,27 +979,6 @@ bridge_fetch_dp_ifaces(struct bridge *br) } free(dpif_ports); } - -/* Returns the idle time that the bridge is currently using. We reduce the - * idle time as the flow table grows, so as to act as a brake on further flow - * table growth. */ -static int -bridge_idle_time(const struct bridge *br) -{ - int idle_time = br->flow_idle_time; - if (idle_time) { - size_t n_flows = hmap_count(&br->ft->flows); - int step = MAX(1, br->flow_idle_time / 5); - while (n_flows > 1000 && idle_time > 0) { - idle_time -= step; - n_flows /= 2; - } - if (idle_time < 1) { - idle_time = 1; - } - } - return idle_time; -} /* Bridge packet processing functions. */ @@ -1060,26 +1031,6 @@ choose_output_iface(const struct port *port, const flow_t *flow, return true; } -static void -bond_account_flow(struct bridge *br, const struct ft_flow *f) -{ - const struct ft_dst *dst; - - if (f->byte_count <= f->last_byte_count) { - /* No bytes to add, so don't waste our time. */ - return; - } - /* XXX return immediately if no bonded interfaces. */ - - for (dst = &f->dsts[0]; dst < &f->dsts[f->n_dsts]; dst++) { - struct port *port = port_from_dp_ifidx(br, dst->dp_ifidx); - if (port && port->n_ifaces >= 2) { - struct bond_entry *e = lookup_bond_entry(port, f->flow.dl_src); - e->tx_bytes += f->byte_count - f->last_byte_count; - } - } -} - static void bond_link_status_update(struct iface *iface, bool carrier) { @@ -1183,7 +1134,7 @@ bond_wait(struct bridge *br) } static bool -set_dst(struct ft_dst *p, const flow_t *flow, +set_dst(struct dst *p, const flow_t *flow, const struct port *in_port, const struct port *out_port, tag_type *tags) { @@ -1206,28 +1157,28 @@ set_dst(struct ft_dst *p, const flow_t *flow, } static void -swap_dst(struct ft_dst *p, struct ft_dst *q) +swap_dst(struct dst *p, struct dst *q) { - struct ft_dst tmp = *p; + struct dst tmp = *p; *p = *q; *q = tmp; } -/* Moves all the ft_dsts with vlan == 'vlan' to the front of the 'n_dsts' in +/* Moves all the dsts with vlan == 'vlan' to the front of the 'n_dsts' in * 'dsts'. (This may help performance by reducing the number of VLAN changes * that we push over OpenFlow. We could in fact fully sort the array by vlan, * but in most cases there are at most two different vlan tags so that's * possibly overkill.) */ static void -partition_dsts(struct ft_dst *dsts, size_t n_dsts, int vlan) +partition_dsts(struct dst *dsts, size_t n_dsts, int vlan) { - struct ft_dst *first = dsts; - struct ft_dst *last = dsts + n_dsts; + struct dst *first = dsts; + struct dst *last = dsts + n_dsts; while (first != last) { /* Invariants: - * - All ft_dsts < first have vlan == 'vlan'. - * - All ft_dsts >= last have vlan != 'vlan'. + * - All dsts < first have vlan == 'vlan'. + * - All dsts >= last have vlan != 'vlan'. * - first < last. */ while (first->vlan == vlan) { if (++first == last) { @@ -1250,36 +1201,6 @@ partition_dsts(struct ft_dst *dsts, size_t n_dsts, int vlan) } } -static void * -add_action_header(struct ofpbuf *buf, uint16_t type) -{ - struct ofp_action_header *oah = ofpbuf_put_zeros(buf, sizeof *oah); - oah->type = htons(type); - oah->len = htons(sizeof *oah); - return oah; -} - -static void -add_output_action(struct ofpbuf *buf, uint16_t dp_ifidx) -{ - struct ofp_action_output *oao = add_action_header(buf, OFPAT_OUTPUT); - oao->port = htons(dp_ifidx); - oao->max_len = htons(0); -} - -static void -add_vlan_action(struct ofpbuf *buf, uint16_t old_vlan, uint16_t new_vlan) -{ - assert(old_vlan != new_vlan); - if (new_vlan == htons(OFP_VLAN_NONE)) { - add_action_header(buf, OFPAT_STRIP_VLAN); - } else { - struct ofp_action_vlan_vid *oavv - = add_action_header(buf, OFPAT_SET_VLAN_VID); - oavv->vlan_vid = htons(new_vlan); - } -} - static int mirror_mask_ffs(mirror_mask_t mask) { @@ -1288,8 +1209,8 @@ mirror_mask_ffs(mirror_mask_t mask) } static bool -dst_is_duplicate(const struct ft_dst *dsts, size_t n_dsts, - const struct ft_dst *test) +dst_is_duplicate(const struct dst *dsts, size_t n_dsts, + const struct dst *test) { size_t i; for (i = 0; i < n_dsts; i++) { @@ -1315,15 +1236,15 @@ port_includes_vlan(const struct port *port, uint16_t vlan) static size_t compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan, const struct port *in_port, const struct port *out_port, - struct ft_dst dsts[], tag_type *tags) + struct dst dsts[], tag_type *tags) { mirror_mask_t mirrors = in_port->src_mirrors; - struct ft_dst *dst = dsts; + struct dst *dst = dsts; size_t i; *tags |= in_port->stp_state_tag; if (out_port == FLOOD_PORT) { - /* XXX use OFPP_FLOOD if no vlans or bonding. */ + /* XXX use ODP_FLOOD if no vlans or bonding. */ /* XXX even better, define each VLAN as a datapath port group */ for (i = 0; i < br->n_ports; i++) { struct port *port = br->ports[i]; @@ -1357,12 +1278,10 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan, if (port->vlan < 0) { dst->vlan = m->out_vlan; } - if (dst->dp_ifidx == flow->in_port) { - if (dst->vlan == vlan) { - /* Don't send out input port on same VLAN. */ - continue; - } - dst->dp_ifidx = OFPP_IN_PORT; + if (dst->dp_ifidx == flow->in_port + && dst->vlan == vlan) { + /* Don't send out input port on same VLAN. */ + continue; } dst++; } @@ -1376,129 +1295,56 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan, return dst - dsts; } -static void -put_actions(const struct ft_dst dsts[], size_t n_dsts, uint16_t flow_vlan, - struct ofpbuf *buf) +static void UNUSED +print_dsts(const struct dst *dsts, size_t n) { - const struct ft_dst *p; - uint16_t vlan = flow_vlan; - for (p = dsts; p < &dsts[n_dsts]; p++) { - if (p->vlan != vlan) { - add_vlan_action(buf, vlan, p->vlan); - vlan = p->vlan; + for (; n--; dsts++) { + printf(">p%"PRIu16, dsts->dp_ifidx); + if (dsts->vlan != OFP_VLAN_NONE) { + printf("v%"PRIu16, dsts->vlan); } - add_output_action(buf, p->dp_ifidx); } } static void -send_packets(struct bridge *br, const flow_t *flow, - const struct ofpbuf *pkt, uint16_t vlan, - const struct port *in_port, const struct port *out_port, - tag_type tags, bool setup_flow) +compose_actions(struct bridge *br, const flow_t *flow, uint16_t vlan, + const struct port *in_port, const struct port *out_port, + tag_type *tags, struct odp_actions *actions) { - struct ft_dst dsts[DP_MAX_PORTS * (MAX_MIRRORS + 1)]; - size_t actions_len; /* Estimated length of actions, in bytes. */ + struct dst dsts[DP_MAX_PORTS * (MAX_MIRRORS + 1)]; size_t n_dsts; + const struct dst *p; + uint16_t cur_vlan; - n_dsts = compose_dsts(br, flow, vlan, in_port, out_port, dsts, &tags); - actions_len = (sizeof(struct ofp_action_header) + 2) * n_dsts; - - if (setup_flow) { - enum { NO_OP, ADD_FLOW, SET_ACTIONS } command; - struct ft_flow *f; - - f = ft_lookup(br->ft, flow, flow_hash(flow, 0)); - if (f) { - if (!ftd_equal(dsts, n_dsts, f->dsts, f->n_dsts)) { - /* Update the flow. Use OFPFC_MODIFY_STRICT instead of - * OFPFC_ADD so that we don't reset the idle-timer - * countdown for this flow. */ - ftf_set_dsts(f, dsts, n_dsts); - command = SET_ACTIONS; - } else { - /* Correct flow is already in the flow table, nothing to do. - * This should only happen on revalidate, since - * process_packet_in() will delete any flow entry for a - * no-match packet-in message. (If it could happen in other - * circumstances then we'd want to arrange to send a packet-out - * below, but there's no need.) */ - command = NO_OP; - } - f->tags = tags; - } else { - f = ftf_create(flow, dsts, n_dsts, tags); - ft_insert(br->ft, f); - command = ADD_FLOW; - } - f->need_drop = false; - - if (command != NO_OP) { - struct ofpbuf abuf; - size_t n_actions; - - ofpbuf_init(&abuf, actions_len); - put_actions(dsts, n_dsts, ntohs(flow->dl_vlan), &abuf); - n_actions = abuf.size / sizeof(union ofp_action); - - if (command == ADD_FLOW) { - ofproto_add_flow(br->ofproto, flow, 0, UINT16_MAX, - abuf.data, n_actions, - pkt, bridge_idle_time(br)); - pkt = NULL; /* Already sent. */ + n_dsts = compose_dsts(br, flow, vlan, in_port, out_port, dsts, tags); - /* ofproto_add_flow() will reset the byte counters. */ - f->last_byte_count = f->byte_count = 0; - } else { - ofproto_set_actions(br->ofproto, flow, abuf.data, n_actions); - } - ofpbuf_uninit(&abuf); - } - } else { - struct ft_flow *f = ft_lookup(br->ft, flow, flow_hash(flow, 0)); - if (f) { - /* XXX delete flow from ft, queue delete-flow openflow message */ + cur_vlan = ntohs(flow->dl_vlan); + for (p = dsts; p < &dsts[n_dsts]; p++) { + union odp_action *a; + if (p->vlan != cur_vlan) { + a = odp_actions_add(actions, ODPAT_SET_VLAN_VID); + a->vlan_vid.vlan_vid = htons(p->vlan); + cur_vlan = p->vlan; } + a = odp_actions_add(actions, ODPAT_OUTPUT); + a->output.port = p->dp_ifidx; } - - /* XXX we should send the packet *before* we set up the flow, so as to not - * reorder packets in the flow. */ - if (pkt) { - struct ofpbuf abuf; - - ofpbuf_init(&abuf, actions_len); - put_actions(dsts, n_dsts, ntohs(flow->dl_vlan), &abuf); - ofproto_send_packet(br->ofproto, flow, - abuf.data, abuf.size / sizeof(union ofp_action), - pkt); - ofpbuf_uninit(&abuf); - } -} - -static bool -is_bcast_arp_reply(const flow_t *flow, const struct ofpbuf *pkt) -{ - return (flow->dl_type == htons(ETH_TYPE_ARP) - && eth_addr_is_broadcast(flow->dl_dst) - && pkt->size >= sizeof(struct arp_eth_header) - && ((struct arp_eth_header *) pkt->data)->ar_op == ARP_OP_REQUEST); } static void -process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt) +process_flow(struct bridge *br, const flow_t *flow, bool revalidating, + struct odp_actions *actions, tag_type *tags) { struct iface *in_iface; struct port *in_port; struct port *out_port = NULL; /* By default, drop the packet/flow. */ - tag_type tags = 0; int vlan; /* Find the interface and port structure for the received packet. */ in_iface = iface_from_dp_ifidx(br, flow->in_port); if (!in_iface) { /* No interface? Something fishy... */ - struct ft_flow *f = ft_lookup(br->ft, flow, flow_hash(flow, 0)); - if (pkt || (f && f->need_drop)) { + if (!revalidating) { /* Odd. A few possible reasons here: * * - We deleted an interface but there are still a few packets @@ -1514,35 +1360,9 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt) VLOG_WARN_RL(&rl, "bridge %s: received packet on unknown " "interface %"PRIu16, br->name, flow->in_port); - - ofproto_add_flow(br->ofproto, flow, 0, UINT16_MAX, - NULL, 0, NULL, bridge_idle_time(br)); - if (f) { - ftf_set_dsts(f, NULL, 0); - f->tags = tags; - } else { - f = ftf_create(flow, NULL, 0, tags); - ft_insert(br->ft, f); - } - - /* Mark the flow as being needed to drop packets. (If we don't do - * this, then the flow will be deleted as soon as we revalidate - * it.) */ - f->need_drop = true; - } else { - /* We're revalidating, not receiving a fresh packet. Most likely, - * this interface existed and has now been deleted from the - * datapath. Drop the flow. */ - assert(f); - - ofproto_delete_flow(br->ofproto, flow, 0, UINT16_MAX); - - /* ofproto_delete_flow() better not call back to - * bridge_flow_expired_ofhook_cb(). */ - ft_remove(br->ft, f); - ftf_destroy(f); - /* 'flow' pointed to &f->flow, so don't access it anymore. */ } + + /* Return without adding any actions, to drop packets on this flow. */ return; } in_port = in_iface->port; @@ -1561,7 +1381,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt) if (in_port->vlan >= 0) { if (vlan) { /* XXX support double tagging? */ - if (pkt) { + if (!revalidating) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "bridge %s: dropping VLAN %"PRIu16" tagged " "packet received on port %s configured with " @@ -1607,7 +1427,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt) /* Drop multicast and broadcast packets on inactive bonded interfaces, to * avoid receiving duplicates. */ if (in_port->n_ifaces > 1 && eth_addr_is_multicast(flow->dl_dst)) { - tags |= in_port->active_iface_tag; + *tags |= in_port->active_iface_tag; if (in_port->active_iface != in_iface->port_ifidx) { goto done; } @@ -1619,7 +1439,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt) int out_port_idx; bool may_learn; - if (!pkt) { + if (revalidating) { /* Don't try to learn from revalidation. */ may_learn = false; } else if (in_port->n_ifaces > 1) { @@ -1631,11 +1451,8 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt) int src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan); may_learn = src_idx < 0 || src_idx == in_port->port_idx; - /* Broadcast ARP replies are an exception to this rule: the host - * has moved to another switch. */ - if (!may_learn && is_bcast_arp_reply(flow, pkt)) { - may_learn = true; - } + /* XXX Need to make an exception for broadcast ARP replies here: + * the host has moved to another switch. */ } else { may_learn = true; } @@ -1659,7 +1476,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt) /* Determine output port. */ out_port_idx = mac_learning_lookup_tag(br->ml, flow->dl_dst, vlan, - &tags); + tags); if (out_port_idx >= 0 && out_port_idx < br->n_ports) { out_port = br->ports[out_port_idx]; } @@ -1684,17 +1501,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt) * them. */ done: - send_packets(br, flow, pkt, vlan, in_port, out_port, tags, - (br->flow_idle_time >= 0 - && (in_port->n_ifaces < 2 - || flow->dl_type != htons(ETH_TYPE_ARP) - || !eth_addr_is_broadcast(flow->dl_dst)))); -} - -static void -revalidate_flow(struct bridge *br, struct ft_flow *f) -{ - process_flow(br, &f->flow, NULL); + compose_actions(br, flow, vlan, in_port, out_port, tags, actions); } /* Careful: 'opp' is in host byte order and opp->port_no is an OFP port @@ -1735,342 +1542,30 @@ bridge_port_changed_ofhook_cb(enum ofp_port_reason reason, } } -static bool -bridge_packet_in_ofhook_cb(const flow_t *flow, const struct ofpbuf *payload, - void *br_) +static void +bridge_normal_ofhook_cb(const flow_t *flow, bool revalidating, + struct odp_actions *actions, tag_type *tags, void *br_) { struct bridge *br = br_; - struct ft_flow *f; - - /* Delete any existing flow from the flow tracker. The flow cannot really - * be in the flow table (otherwise we wouldn't be getting called). */ - f = ft_lookup(br->ft, flow, flow_hash(flow, 0)); - if (f) { - ft_remove(br->ft, f); - ftf_destroy(f); - } +#if 0 if (flow->dl_type == htons(OFP_DL_TYPE_NOT_ETH_TYPE) && eth_addr_equals(flow->dl_dst, stp_eth_addr)) { brstp_receive(br, flow, payload); return true; } +#endif - process_flow(br, flow, payload); - - return true; -} - -static void -bridge_flow_expired_ofhook_cb(const struct ofexpired *expired, void *br_) -{ - struct bridge *br = br_; - struct ft_flow *f; - - f = ft_lookup(br->ft, &expired->flow, flow_hash(&expired->flow, 0)); - if (f) { - /* Update statistics. */ - f->last_byte_count = f->byte_count; - f->byte_count = expired->byte_count; - bond_account_flow(br, f); - - ft_remove(br->ft, f); - ftf_destroy(f); - } else if (VLOG_IS_DBG_ENABLED()) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_DBG_RL(&rl, "received flow expiration for flow not in table"); - } + process_flow(br, flow, revalidating, actions, tags); } static struct ofhooks bridge_ofhooks = { bridge_port_changed_ofhook_cb, - bridge_packet_in_ofhook_cb, - bridge_flow_expired_ofhook_cb, + NULL, + NULL, + bridge_normal_ofhook_cb, }; -/* Flow statistics collection. */ - -struct slave_balance { - struct iface *iface; - uint64_t tx_bytes; - struct bond_entry **hashes; - size_t n_hashes; -}; - -/* Sorts pointers to pointers to bond_entries in ascending order by the - * interface to which they are assigned, and within a single interface in - * ascending order of bytes transmitted. */ -static int -compare_bond_entries(const void *a_, const void *b_) -{ - const struct bond_entry *const *ap = a_; - const struct bond_entry *const *bp = b_; - const struct bond_entry *a = *ap; - const struct bond_entry *b = *bp; - if (a->iface_idx != b->iface_idx) { - return a->iface_idx > b->iface_idx ? 1 : -1; - } else if (a->tx_bytes != b->tx_bytes) { - return a->tx_bytes > b->tx_bytes ? 1 : -1; - } else { - return 0; - } -} - -/* Sorts slave_balances in *descending* order by number of bytes - * transmitted. */ -static int -compare_slave_balance(const void *a_, const void *b_) -{ - const struct slave_balance *a = a_; - const struct slave_balance *b = b_; - return a->tx_bytes > b->tx_bytes ? -1 : a->tx_bytes < b->tx_bytes; -} - -static void -swap_bals(struct slave_balance *a, struct slave_balance *b) -{ - struct slave_balance tmp = *a; - *a = *b; - *b = tmp; -} - -static void -resort_bals(struct slave_balance *p, struct slave_balance *bals, size_t n_bals) -{ - if (n_bals > 1) { - for (; p > bals && p->tx_bytes > p[-1].tx_bytes; p--) { - swap_bals(p, p - 1); - } - for (; p < &bals[n_bals - 1] && p->tx_bytes < p[1].tx_bytes; p++) { - swap_bals(p, p + 1); - } - } -} - -static void UNUSED -log_bals(const char *title, const struct slave_balance *bals, size_t n_bals, - struct port *port) -{ - const struct slave_balance *b; - - if (VLOG_IS_DBG_ENABLED()) { - VLOG_DBG("slave balance %s:", title); - for (b = bals; b < bals + n_bals; b++) { - size_t i; - - VLOG_DBG("\t%s: %"PRIu64" bytes over:", - b->iface->name, b->tx_bytes); - for (i = 0; i < b->n_hashes; i++) { - const struct bond_entry *e = b->hashes[i]; - VLOG_DBG("\t\thash %td: %"PRIu64" bytes", - e - port->bond_hash, e->tx_bytes); - } - } - } -} - -static void -bond_rebalance_port(struct port *port) -{ - struct slave_balance bals[DP_MAX_PORTS]; - struct bond_entry *hashes[BOND_MASK + 1]; - struct slave_balance *b, *least_loaded; - struct bond_entry *e; - size_t i; - - for (b = bals; b < &bals[port->n_ifaces]; b++) { - b->iface = port->ifaces[b - bals]; - b->tx_bytes = 0; - b->hashes = NULL; - b->n_hashes = 0; - } - for (i = 0; i <= BOND_MASK; i++) { - hashes[i] = &port->bond_hash[i]; - } - qsort(hashes, BOND_MASK + 1, sizeof *hashes, compare_bond_entries); - for (i = 0; i <= BOND_MASK; i++) { - e = hashes[i]; - if (e->iface_idx >= 0 && e->iface_idx < port->n_ifaces) { - b = &bals[e->iface_idx]; - b->tx_bytes += e->tx_bytes; - if (!b->hashes) { - b->hashes = &hashes[i]; - } - b->n_hashes++; - } - } - - /* Sort in decreasing order of tx_bytes. */ - qsort(bals, port->n_ifaces, sizeof *bals, compare_slave_balance); - - - /* Shift load from the most-heavily-loaded slaves to the - * least-heavily-loaded slaves. */ - least_loaded = &bals[port->n_ifaces - 1]; - //log_bals("before", bals, port->n_ifaces, port); - for (b = bals; b < least_loaded; ) { - uint64_t overload = b->tx_bytes - least_loaded->tx_bytes; - if (overload < least_loaded->tx_bytes >> 5 || overload < 100000) { - /* The extra load on this slave (and all less-loaded slaves), - * compared to that of the least-loaded slave, is less than ~3%, or - * it is less than ~1Mbps. No point in rebalancing. */ - break; - } - - if (b->n_hashes == 1) { - /* This slave only carries a single MAC hash, so we can't shift any - * load away from it, even though we want to. */ - b++; - continue; - } - - for (i = 0; i < b->n_hashes; i++) { - e = b->hashes[i]; - if (least_loaded->tx_bytes + e->tx_bytes - < b->tx_bytes - e->tx_bytes) { - /* Delete element from e->hashes. */ - if (!i) { - b->hashes++; - } else { - memmove(b->hashes + i, b->hashes + i + 1, - (b->n_hashes - (i + 1)) * sizeof *b->hashes); - } - b->n_hashes--; - - /* Shift load away from 'b'. */ - b->tx_bytes -= e->tx_bytes; - resort_bals(b, bals, port->n_ifaces); - - /* Shift load to 'least_loaded'. */ - tag_set_add(&port->bridge->revalidate_set, e->iface_tag); - e->iface_idx = least_loaded->iface->port_ifidx; - e->iface_tag = tag_create_random(); - least_loaded->tx_bytes += e->tx_bytes; - resort_bals(least_loaded, bals, port->n_ifaces); - goto again; - } - } - b++; - - again: ; - } - //log_bals("after", bals, port->n_ifaces, port); - - /* Implement exponentially weighted moving average. A weight of 1/2 causes - * historical data to decay to <1% in 7 rebalancing runs. */ - for (e = &port->bond_hash[0]; e <= &port->bond_hash[BOND_MASK]; e++) { - e->tx_bytes /= 2; - } -} - -static void -bond_rebalance(struct bridge *br) -{ - size_t i; - - for (i = 0; i < br->n_ports; i++) { - struct port *port = br->ports[i]; - if (port->n_ifaces < 2) { - continue; - } - - bond_rebalance_port(port); - } -} - -static void -request_flow_stats(struct bridge *br) -{ - /* This ft_dst will never appear as a valid flow's action. Thus, we can - * set it as a flow's action to force revalidation to update that flow. */ - static const struct ft_dst invalid_dst = {0xffff, 0xffff}; - - struct odp_flow *flows, *odp_flow; - size_t n_flows; - int error; - - tag_type flowstats_tag; - struct ft *new_ft; - size_t n_tagged; - - error = dpif_flow_list_all(&br->dpif, &flows, &n_flows); - if (error) { - return; - } - - new_ft = ft_create(); - flowstats_tag = tag_create_random(); - n_tagged = 0; - for (odp_flow = flows; odp_flow < &flows[n_flows]; odp_flow++) { - const flow_t *flow = &odp_flow->key; - size_t hash = flow_hash(flow, 0); - struct ft_flow *f = ft_lookup(br->ft, flow, hash); - if (f) { - /* Move from br->ft to new_ft. */ - ft_remove(br->ft, f); - hmap_insert_fast(&new_ft->flows, &f->node, f->node.hash); - - /* Update statistics. - * XXX is this still accurate with the new datapath? */ - f->last_byte_count = f->byte_count; - f->byte_count = odp_flow->stats.n_bytes; - - bond_account_flow(br, f); - - /* XXX Should we verify that the flow's actions are what we - * expect? (This used to be easy; now it's harder.) */ - } else { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - f = ft_lookup(new_ft, flow, hash); - if (!f) { - if (!VLOG_DROP_WARN(&rl)) { - char *flow_string = flow_to_string(flow); - VLOG_WARN("unexpected flow in flow table: %s", - flow_string); - free(flow_string); - } - f = ftf_create(flow, &invalid_dst, 1, flowstats_tag); - hmap_insert_fast(&new_ft->flows, &f->node, f->node.hash); - f->tags |= flowstats_tag; - n_tagged++; - f->last_byte_count = f->byte_count = odp_flow->stats.n_bytes; - } else { - VLOG_WARN_RL(&rl, "duplicate flow in flow stats reply"); - } - } - } - - /* Delete all the flows that remain in br->ft, replacing them by the ones - * from new_ft. */ - hmap_expand(&new_ft->flows); - hmap_swap(&br->ft->flows, &new_ft->flows); - ft_destroy(new_ft); - - /* If we tagged anything for revalidation, add that tag to the revalidation - * set. */ - if (n_tagged) { - tag_set_add(&br->revalidate_set, flowstats_tag); - } - - /* Rebalance any bonded ports. */ - bond_rebalance(br); -} - -static void -flowstats_run(struct bridge *br) -{ - if (time_now() >= br->next_stats_request) { - request_flow_stats(br); - br->next_stats_request = time_now() + 10; - } -} - -static void -flowstats_wait(struct bridge *br) -{ - poll_timer_wait((br->next_stats_request - time_now()) * 1000); -} - /* Port functions. */ static void @@ -2698,7 +2193,7 @@ brstp_send_bpdu(struct ofpbuf *pkt, int port_no, void *br_) action.output.len = htons(sizeof action); action.output.port = htons(port_no); - flow_extract(pkt, htons(OFPP_NONE), &flow); + flow_extract(pkt, ODPP_NONE, &flow); ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt); } ofpbuf_delete(pkt); @@ -2876,40 +2371,3 @@ brstp_wait(struct bridge *br) poll_timer_wait(1000); } } - -static void -brstp_receive(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt) -{ - struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - struct ofpbuf payload = *pkt; - struct eth_header *eth; - struct llc_header *llc; - struct stp_port *sp; - - /* Find the interface and port structure for the received packet. */ - if (flow->in_port >= STP_MAX_PORTS) { - return; - } - sp = stp_get_port(br->stp, flow->in_port); - if (stp_port_get_state(sp) == STP_DISABLED) { - return; - } - - /* Check LLC DSAP. (Caller already verified dl_type and dl_dst.) */ - eth = payload.data; - llc = ofpbuf_at_assert(&payload, sizeof(struct eth_header), sizeof *llc); - if (llc->llc_dsap != STP_LLC_DSAP) { - VLOG_DBG_RL(&rl, "bad DSAP 0x%02"PRIx8" received on STP multicast " - "address", llc->llc_dsap); - return; - } - - /* Trim off padding on payload. */ - if (payload.size > ntohs(eth->eth_type) + ETH_HEADER_LEN) { - payload.size = ntohs(eth->eth_type) + ETH_HEADER_LEN; - } - if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) { - struct stp_port *p = stp_get_port(br->stp, flow->in_port); - stp_received_bpdu(p, payload.data, payload.size); - } -} diff --git a/vswitchd/flowtrack.c b/vswitchd/flowtrack.c deleted file mode 100644 index bf3cce9c..00000000 --- a/vswitchd/flowtrack.c +++ /dev/null @@ -1,186 +0,0 @@ -/* Copyright (c) 2008, 2009 Nicira Networks - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * In addition, as a special exception, Nicira Networks gives permission - * to link the code of its release of vswitchd with the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the same - * license as the "OpenSSL" library), and distribute the linked - * executables. You must obey the GNU General Public License in all - * respects for all of the code used other than "OpenSSL". If you modify - * this file, you may extend this exception to your version of the file, - * but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. - */ - -#include -#include "flowtrack.h" -#include -#include -#include -#include "flow.h" -#include "openflow/openflow.h" -#include "util.h" - -static bool -is_vlan_action(const struct ofp_action_header *oah, uint16_t vlan) -{ - if (vlan == htons(OFP_VLAN_NONE)) { - return (oah->type == htons(OFPAT_STRIP_VLAN) - && oah->len != htons(sizeof *oah)); - } else { - const struct ofp_action_vlan_vid *oavv - = (const struct ofp_action_vlan_vid *) oah; - return (oavv->type == htons(OFPAT_SET_VLAN_VID) - && oavv->len == htons(sizeof *oavv) - && oavv->vlan_vid == htons(vlan)); - } -} - -static bool -is_output_action(const struct ofp_action_header *oah, uint16_t port) -{ - const struct ofp_action_output *oao - = (const struct ofp_action_output *) oah; - return (oao->type == htons(OFPAT_OUTPUT) - && oao->len == htons(sizeof *oao) - && oao->port == htons(port)); -} - -bool -ftd_equal_actions(const struct ft_dst *dsts, size_t n_dsts, - const struct ofp_action_header *oahs, size_t n_oahs, - uint16_t flow_vlan) -{ - const struct ft_dst *dst; - uint16_t vlan = flow_vlan; - for (dst = dsts; dst < &dsts[n_dsts]; dst++) { - if (dst->vlan != vlan) { - vlan = dst->vlan; - if (!n_oahs-- || !is_vlan_action(oahs++, vlan)) { - return false; - } - } - if (!n_oahs-- || !is_output_action(oahs++, dst->dp_ifidx)) { - return false; - } - } - return !n_oahs; -} - -void -ftd_print(const struct ft_dst *dsts, size_t n) -{ - for (; n--; dsts++) { - printf(">p%"PRIu16, dsts->dp_ifidx); - if (dsts->vlan != OFP_VLAN_NONE) { - printf("v%"PRIu16, dsts->vlan); - } - } -} - -struct ft_flow * -ftf_create(const flow_t *flow, - const struct ft_dst dsts[], size_t n_dsts, - tag_type tags) -{ - struct ft_flow *f; - - assert(!flow->reserved); - f = xmalloc(sizeof *f); - f->tags = tags; - f->flow = *flow; - f->need_drop = false; - f->node.hash = flow_hash(&f->flow, 0); - f->dsts = &f->one_dst; - ftf_set_dsts(f, dsts, n_dsts); - f->last_byte_count = f->byte_count = 0; - return f; -} - -void -ftf_destroy(struct ft_flow *f) -{ - if (f) { - ftf_set_dsts(f, NULL, 0); - free(f); - } -} - -void -ftf_set_dsts(struct ft_flow *f, const struct ft_dst dsts[], size_t n_dsts) -{ - if (f->dsts != &f->one_dst) { - free(f->dsts); - } - - f->n_dsts = n_dsts; - if (n_dsts > 1) { - f->dsts = xmemdup(dsts, sizeof *f->dsts * n_dsts); - } else { - f->dsts = &f->one_dst; - if (n_dsts) { - f->one_dst = *dsts; - } - } -} - -struct ft * -ft_create(void) -{ - struct ft *ft = xcalloc(1, sizeof *ft); - hmap_init(&ft->flows); - return ft; -} - -void -ft_destroy(struct ft *ft) -{ - if (ft) { - struct ft_flow *f, *next; - - HMAP_FOR_EACH_SAFE (f, next, struct ft_flow, node, &ft->flows) { - ftf_destroy(f); - } - hmap_destroy(&ft->flows); - free(ft); - } -} - -struct ft_flow * -ft_lookup(const struct ft *ft, const flow_t *target, size_t hash) -{ - struct ft_flow *f; - - assert(!target->reserved); - HMAP_FOR_EACH_WITH_HASH (f, struct ft_flow, node, hash, &ft->flows) { - if (flow_equal(&f->flow, target)) { - return f; - } - } - return NULL; -} - -void -ft_remove(struct ft *ft, struct ft_flow *f) -{ - hmap_remove(&ft->flows, &f->node); - /* It's the caller's responsible to free 'f', if desired. */ -} - -void -ft_insert(struct ft *ft, struct ft_flow *f) -{ - hmap_insert(&ft->flows, &f->node, f->node.hash); -} diff --git a/vswitchd/flowtrack.h b/vswitchd/flowtrack.h deleted file mode 100644 index c0c40c65..00000000 --- a/vswitchd/flowtrack.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2008, 2009 Nicira Networks - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * In addition, as a special exception, Nicira Networks gives permission - * to link the code of its release of vswitchd with the OpenSSL project's - * "OpenSSL" library (or with modified versions of it that use the same - * license as the "OpenSSL" library), and distribute the linked - * executables. You must obey the GNU General Public License in all - * respects for all of the code used other than "OpenSSL". If you modify - * this file, you may extend this exception to your version of the file, - * but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. - */ - -#ifndef VSWITCHD_FLOWTRACK_H -#define VSWITCHD_FLOWTRACK_H 1 - -#include -#include -#include -#include "flow.h" -#include "hmap.h" -#include "tag.h" - -struct ofp_action_header; - -struct ft_dst { - uint16_t vlan; - uint16_t dp_ifidx; -}; - -static inline bool ftd_equal(const struct ft_dst *, size_t, - const struct ft_dst *, size_t); -bool ftd_equal_actions(const struct ft_dst *, size_t, - const struct ofp_action_header *, size_t n_oah, - uint16_t flow_vlan); -void ftd_print(const struct ft_dst *, size_t); - -static inline bool -ftd_equal(const struct ft_dst *a, size_t an, - const struct ft_dst *b, size_t bn) -{ - return an == bn && !memcmp(a, b, an * sizeof *a); -} - - -struct ft_flow { - tag_type tags; - struct hmap_node node; - flow_t flow; - bool need_drop; - - /* Statistics. */ - uint64_t last_byte_count; - uint64_t byte_count; - - /* Actions. */ - struct ft_dst *dsts; - size_t n_dsts; - struct ft_dst one_dst; -}; - -struct ft_flow *ftf_create(const flow_t *, - const struct ft_dst[], size_t n_dsts, - tag_type tags); -void ftf_destroy(struct ft_flow *); -void ftf_set_dsts(struct ft_flow *, const struct ft_dst[], size_t n_dsts); - -struct ft { - struct hmap flows; -}; - -struct ft *ft_create(void); -void ft_destroy(struct ft *); -void ft_swap(struct ft *, struct ft *); -struct ft_flow *ft_lookup(const struct ft *, const flow_t *, size_t hash); -void ft_remove(struct ft *, struct ft_flow *); -void ft_insert(struct ft *, struct ft_flow *); - -#endif /* vswitchd/flowtrack.h */ -- 2.30.2