X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Flearning-switch.c;h=aba3525fdc03472d1200da8d68ce6a8df72d52fe;hb=abfec865566e6cce961cc8660de1ddfdc85dae5f;hp=97c424a6be865491940e62c2918a95d3f4cfc23c;hpb=c71270b7aefddd967d7dd5446f7701241380b09d;p=openvswitch diff --git a/lib/learning-switch.c b/lib/learning-switch.c index 97c424a6..aba3525f 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -26,6 +26,7 @@ #include "flow.h" #include "mac-learning.h" #include "ofpbuf.h" +#include "ofp-parse.h" #include "ofp-print.h" #include "ofp-util.h" #include "openflow/openflow.h" @@ -35,10 +36,10 @@ #include "stp.h" #include "timeval.h" #include "vconn.h" +#include "vlog.h" #include "xtoxll.h" -#define THIS_MODULE VLM_learning_switch -#include "vlog.h" +VLOG_DEFINE_THIS_MODULE(learning_switch) enum port_state { P_DISABLED = 1 << 0, @@ -84,6 +85,8 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300); static void queue_tx(struct lswitch *, struct rconn *, struct ofpbuf *); static void send_features_request(struct lswitch *, struct rconn *); +static void send_default_flows(struct lswitch *sw, struct rconn *rconn, + FILE *default_flows); static void schedule_query(struct lswitch *, long long int delay); static bool may_learn(const struct lswitch *, uint16_t port_no); static bool may_recv(const struct lswitch *, uint16_t port_no, @@ -107,10 +110,17 @@ static packet_handler_func process_stats_reply; * after the given number of seconds (or never expire, if 'max_idle' is * OFP_FLOW_PERMANENT). Otherwise, the new switch will process every packet. * + * The caller may provide the file stream 'default_flows' that defines + * default flows that should be pushed when a switch connects. Each + * line is a flow entry in the format described for "add-flows" command + * in the Flow Syntax section of the ovs-ofct(8) man page. The caller + * is responsible for closing the stream. + * * 'rconn' is used to send out an OpenFlow features request. */ struct lswitch * lswitch_create(struct rconn *rconn, bool learn_macs, - bool exact_flows, int max_idle, bool action_normal) + bool exact_flows, int max_idle, bool action_normal, + FILE *default_flows) { struct lswitch *sw; size_t i; @@ -140,6 +150,9 @@ lswitch_create(struct rconn *rconn, bool learn_macs, sw->port_states[i] = P_DISABLED; } send_features_request(sw, rconn); + if (default_flows) { + send_default_flows(sw, rconn, default_flows); + } return sw; } @@ -359,6 +372,53 @@ send_features_request(struct lswitch *sw, struct rconn *rconn) } } +static void +send_default_flows(struct lswitch *sw, struct rconn *rconn, + FILE *default_flows) +{ + char line[1024]; + + while (fgets(line, sizeof line, default_flows)) { + struct ofpbuf *b; + struct ofp_flow_mod *ofm; + uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; + struct ofp_match match; + + char *comment; + + /* Delete comments. */ + comment = strchr(line, '#'); + if (comment) { + *comment = '\0'; + } + + /* Drop empty lines. */ + if (line[strspn(line, " \t\n")] == '\0') { + continue; + } + + /* Parse and send. str_to_flow() will expand and reallocate the data + * in 'buffer', so we can't keep pointers to across the str_to_flow() + * call. */ + make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &b); + parse_ofp_str(line, &match, b, + NULL, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); + ofm = b->data; + ofm->match = match; + ofm->command = htons(OFPFC_ADD); + ofm->cookie = htonll(cookie); + ofm->idle_timeout = htons(idle_timeout); + ofm->hard_timeout = htons(hard_timeout); + ofm->buffer_id = htonl(UINT32_MAX); + ofm->priority = htons(priority); + + update_openflow_length(b); + queue_tx(sw, rconn, b); + } +} + static void queue_tx(struct lswitch *sw, struct rconn *rconn, struct ofpbuf *b) { @@ -473,22 +533,29 @@ process_packet_in(struct lswitch *sw, struct rconn *rconn, void *opi_) out_port = lswitch_choose_destination(sw, &flow); /* Make actions. */ - memset(actions, 0, sizeof actions); if (out_port == OFPP_NONE) { actions_len = 0; } else if (sw->queue == UINT32_MAX || out_port >= OFPP_MAX) { - struct ofp_action_output *oao = (struct ofp_action_output *) actions; - oao->type = htons(OFPAT_OUTPUT); - oao->len = htons(sizeof *oao); - oao->port = htons(out_port); - actions_len = sizeof *oao; + struct ofp_action_output oao; + + memset(&oao, 0, sizeof oao); + oao.type = htons(OFPAT_OUTPUT); + oao.len = htons(sizeof oao); + oao.port = htons(out_port); + + memcpy(actions, &oao, sizeof oao); + actions_len = sizeof oao; } else { - struct ofp_action_enqueue *oae = (struct ofp_action_enqueue *) actions; - oae->type = htons(OFPAT_ENQUEUE); - oae->len = htons(sizeof *oae); - oae->port = htons(out_port); - oae->queue_id = htonl(sw->queue); - actions_len = sizeof *oae; + struct ofp_action_enqueue oae; + + memset(&oae, 0, sizeof oae); + oae.type = htons(OFPAT_ENQUEUE); + oae.len = htons(sizeof oae); + oae.port = htons(out_port); + oae.queue_id = htonl(sw->queue); + + memcpy(actions, &oae, sizeof oae); + actions_len = sizeof oae; } assert(actions_len <= sizeof actions);