X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=43054fa335e8465a80b528f18ec137fe9d9edd4e;hb=66aeba23bd8effd71e0a3cf9c0cab75f3d75f6f1;hp=2894e2d331e9799f8c4c2788d2e361ed6d4fca60;hpb=4836f9f2bfa5dc0531bd1d828aae96ccd6b415cb;p=sliver-openvswitch.git diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 2894e2d33..43054fa33 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -35,6 +35,7 @@ #include "netflow.h" #include "odp-util.h" #include "ofp-print.h" +#include "ofproto-sflow.h" #include "ofpbuf.h" #include "openflow/nicira-ext.h" #include "openflow/openflow.h" @@ -60,10 +61,7 @@ #define THIS_MODULE VLM_ofproto #include "vlog.h" -enum { - DP_GROUP_FLOOD = 0, - DP_GROUP_ALL = 1 -}; +#include "sflow_api.h" enum { TABLEID_HASH = 0, @@ -209,6 +207,7 @@ struct ofproto { struct pinsched *miss_sched, *action_sched; struct executer *executer; struct netflow *netflow; + struct ofproto_sflow *sflow; /* Flow table. */ struct classifier cls; @@ -253,7 +252,8 @@ static void handle_odp_msg(struct ofproto *, struct ofpbuf *); static void handle_openflow(struct ofconn *, struct ofproto *, struct ofpbuf *); -static void refresh_port_group(struct ofproto *, unsigned int group); +static void refresh_port_groups(struct ofproto *); + static void update_port(struct ofproto *, const char *devname); static int init_ports(struct ofproto *); static void reinit_ports(struct ofproto *); @@ -282,7 +282,7 @@ ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux, dpif_close(dpif); return error; } - error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION); + error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION | ODPL_SFLOW); if (error) { VLOG_ERR("failed to listen on datapath %s: %s", datapath, strerror(error)); @@ -316,6 +316,7 @@ ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux, p->miss_sched = p->action_sched = NULL; p->executer = NULL; p->netflow = NULL; + p->sflow = NULL; /* Initialize flow table. */ classifier_init(&p->cls); @@ -548,6 +549,30 @@ ofproto_set_netflow(struct ofproto *ofproto, } } +void +ofproto_set_sflow(struct ofproto *ofproto, + const struct ofproto_sflow_options *oso) +{ + struct ofproto_sflow *os = ofproto->sflow; + if (oso) { + if (!os) { + struct ofport *ofport; + unsigned int odp_port; + + os = ofproto->sflow = ofproto_sflow_create(ofproto->dpif); + refresh_port_groups(ofproto); + PORT_ARRAY_FOR_EACH (ofport, &ofproto->ports, odp_port) { + ofproto_sflow_add_port(os, odp_port, + netdev_get_name(ofport->netdev)); + } + } + ofproto_sflow_set_options(os, oso); + } else { + ofproto_sflow_destroy(os); + ofproto->sflow = NULL; + } +} + void ofproto_set_failure(struct ofproto *ofproto, bool fail_open) { @@ -718,6 +743,7 @@ ofproto_destroy(struct ofproto *p) pinsched_destroy(p->action_sched); executer_destroy(p->executer); netflow_destroy(p->netflow); + ofproto_sflow_destroy(p->sflow); switch_status_unregister(p->ss_cat); @@ -870,6 +896,9 @@ ofproto_run1(struct ofproto *p) if (p->netflow) { netflow_run(p->netflow); } + if (p->sflow) { + ofproto_sflow_run(p->sflow); + } return 0; } @@ -926,6 +955,9 @@ ofproto_wait(struct ofproto *p) if (p->executer) { executer_wait(p->executer); } + if (p->sflow) { + ofproto_sflow_wait(p->sflow); + } if (!tag_set_is_empty(&p->revalidate_set)) { poll_immediate_wake(); } @@ -1066,7 +1098,7 @@ reinit_ports(struct ofproto *p) svec_destroy(&devnames); } -static void +static size_t refresh_port_group(struct ofproto *p, unsigned int group) { uint16_t *ports; @@ -1085,13 +1117,18 @@ refresh_port_group(struct ofproto *p, unsigned int group) } dpif_port_group_set(p->dpif, group, ports, n_ports); free(ports); + + return n_ports; } static void refresh_port_groups(struct ofproto *p) { - refresh_port_group(p, DP_GROUP_FLOOD); - refresh_port_group(p, DP_GROUP_ALL); + size_t n_flood = refresh_port_group(p, DP_GROUP_FLOOD); + size_t n_all = refresh_port_group(p, DP_GROUP_ALL); + if (p->sflow) { + ofproto_sflow_set_group_sizes(p->sflow, n_flood, n_all); + } } static struct ofport * @@ -1190,19 +1227,29 @@ send_port_status(struct ofproto *p, const struct ofport *ofport, static void ofport_install(struct ofproto *p, struct ofport *ofport) { + uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no); + const char *netdev_name = (const char *) ofport->opp.name; + netdev_monitor_add(p->netdev_monitor, ofport->netdev); - port_array_set(&p->ports, ofp_port_to_odp_port(ofport->opp.port_no), - ofport); - shash_add(&p->port_by_name, (char *) ofport->opp.name, ofport); + port_array_set(&p->ports, odp_port, ofport); + shash_add(&p->port_by_name, netdev_name, ofport); + if (p->sflow) { + ofproto_sflow_add_port(p->sflow, odp_port, netdev_name); + } } static void ofport_remove(struct ofproto *p, struct ofport *ofport) { + uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no); + netdev_monitor_remove(p->netdev_monitor, ofport->netdev); - port_array_set(&p->ports, ofp_port_to_odp_port(ofport->opp.port_no), NULL); + port_array_set(&p->ports, odp_port, NULL); shash_delete(&p->port_by_name, shash_find(&p->port_by_name, (char *) ofport->opp.name)); + if (p->sflow) { + ofproto_sflow_del_port(p->sflow, odp_port); + } } static void @@ -1628,7 +1675,7 @@ rule_install(struct ofproto *p, struct rule *rule, struct rule *displaced_rule) &put)) { rule->installed = true; if (displaced_rule) { - update_stats(p, rule, &put.flow.stats); + update_stats(p, displaced_rule, &put.flow.stats); rule_post_uninstall(p, displaced_rule); } } @@ -1652,14 +1699,27 @@ rule_reinstall(struct ofproto *ofproto, struct rule *rule) static void rule_update_actions(struct ofproto *ofproto, struct rule *rule) { - bool actions_changed = rule_make_actions(ofproto, rule, NULL); + bool actions_changed; + uint16_t new_out_iface, old_out_iface; + + old_out_iface = rule->nf_flow.output_iface; + actions_changed = rule_make_actions(ofproto, rule, NULL); + if (rule->may_install) { if (rule->installed) { if (actions_changed) { - /* XXX should really do rule_post_uninstall() for the *old* set - * of actions, and distinguish the old stats from the new. */ struct odp_flow_put put; - do_put_flow(ofproto, rule, ODPPF_CREATE | ODPPF_MODIFY, &put); + do_put_flow(ofproto, rule, ODPPF_CREATE | ODPPF_MODIFY + | ODPPF_ZERO_STATS, &put); + update_stats(ofproto, rule, &put.flow.stats); + + /* Temporarily set the old output iface so that NetFlow + * messages have the correct output interface for the old + * stats. */ + new_out_iface = rule->nf_flow.output_iface; + rule->nf_flow.output_iface = old_out_iface; + rule_post_uninstall(ofproto, rule); + rule->nf_flow.output_iface = new_out_iface; } } else { rule_install(ofproto, rule, NULL); @@ -2147,11 +2207,21 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, oa->nw_addr.nw_addr = ia->nw_addr.nw_addr; break; + case OFPAT_SET_NW_DST: + oa = odp_actions_add(ctx->out, ODPAT_SET_NW_DST); + oa->nw_addr.nw_addr = ia->nw_addr.nw_addr; + break; + case OFPAT_SET_TP_SRC: oa = odp_actions_add(ctx->out, ODPAT_SET_TP_SRC); oa->tp_port.tp_port = ia->tp_port.tp_port; break; + case OFPAT_SET_TP_DST: + oa = odp_actions_add(ctx->out, ODPAT_SET_TP_DST); + oa->tp_port.tp_port = ia->tp_port.tp_port; + break; + case OFPAT_VENDOR: xlate_nicira_action(ctx, (const struct nx_action_header *) ia); break; @@ -2268,7 +2338,7 @@ update_port_config(struct ofproto *p, struct ofport *port, #undef REVALIDATE_BITS if (mask & OFPPC_NO_FLOOD) { port->opp.config ^= OFPPC_NO_FLOOD; - refresh_port_group(p, DP_GROUP_FLOOD); + refresh_port_groups(p); } if (mask & OFPPC_NO_PACKET_IN) { port->opp.config ^= OFPPC_NO_PACKET_IN; @@ -3085,7 +3155,7 @@ handle_openflow(struct ofconn *ofconn, struct ofproto *p, } static void -handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) +handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet) { struct odp_msg *msg = packet->data; uint16_t in_port = odp_port_to_ofp_port(msg->port); @@ -3093,14 +3163,6 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) struct ofpbuf payload; flow_t flow; - /* Handle controller actions. */ - if (msg->type == _ODPL_ACTION_NR) { - COVERAGE_INC(ofproto_ctlr_action); - pinsched_send(p->action_sched, in_port, packet, - send_packet_in_action, p); - return; - } - payload.data = msg + 1; payload.size = msg->length - sizeof *msg; flow_extract(&payload, msg->port, &flow); @@ -3170,6 +3232,36 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) ofpbuf_delete(packet); } } + +static void +handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) +{ + struct odp_msg *msg = packet->data; + + switch (msg->type) { + case _ODPL_ACTION_NR: + COVERAGE_INC(ofproto_ctlr_action); + pinsched_send(p->action_sched, odp_port_to_ofp_port(msg->port), packet, + send_packet_in_action, p); + break; + + case _ODPL_SFLOW_NR: + if (p->sflow) { + ofproto_sflow_received(p->sflow, msg); + } + ofpbuf_delete(packet); + break; + + case _ODPL_MISS_NR: + handle_odp_miss_msg(p, packet); + break; + + default: + VLOG_WARN_RL(&rl, "received ODP message of unexpected type %"PRIu32, + msg->type); + break; + } +} static void revalidate_cb(struct cls_rule *sub_, void *cbdata_) @@ -3300,19 +3392,23 @@ expire_rule(struct cls_rule *cls_rule, void *p_) } COVERAGE_INC(ofproto_expired); + + /* Update stats. This code will be a no-op if the rule expired + * due to an idle timeout. */ if (rule->cr.wc.wildcards) { - /* Update stats. (This code will be a no-op if the rule expired - * due to an idle timeout, because in that case the rule has no - * subrules left.) */ struct rule *subrule, *next; LIST_FOR_EACH_SAFE (subrule, next, struct rule, list, &rule->list) { rule_remove(p, subrule); } + } else { + rule_uninstall(p, rule); } - send_flow_exp(p, rule, now, - (now >= hard_expire - ? OFPER_HARD_TIMEOUT : OFPER_IDLE_TIMEOUT)); + if (!rule_is_hidden(rule)) { + send_flow_exp(p, rule, now, + (now >= hard_expire + ? OFPER_HARD_TIMEOUT : OFPER_IDLE_TIMEOUT)); + } rule_remove(p, rule); }