X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=switch%2Fdatapath.c;h=31b9af2f5053e7f994a78d897222495ce3888709;hb=b3b28afb7bef9094d05fcc8c1be4a41f9f1d5bfe;hp=4ec436e0aad667560ea04c61a32d5bb41252cfe5;hpb=6ca5840e489ee880ed22e581ff406f5394bed25e;p=sliver-openvswitch.git diff --git a/switch/datapath.c b/switch/datapath.c index 4ec436e0a..31b9af2f5 100644 --- a/switch/datapath.c +++ b/switch/datapath.c @@ -48,6 +48,7 @@ #include "rconn.h" #include "vconn.h" #include "table.h" +#include "timeval.h" #include "xtoxll.h" #define THIS_MODULE VLM_datapath @@ -113,7 +114,9 @@ struct datapath { struct sw_chain *chain; /* Forwarding rules. */ - struct ofp_switch_config config; + /* Configuration set from controller. */ + uint16_t flags; + uint16_t miss_send_len; /* Switch ports. */ struct sw_port ports[OFPP_MAX]; @@ -130,7 +133,8 @@ void dp_output_port(struct datapath *, struct buffer *, void dp_update_port_flags(struct datapath *dp, const struct ofp_phy_port *opp); void dp_output_control(struct datapath *, struct buffer *, int in_port, size_t max_len, int reason); -static void send_flow_expired(struct datapath *, struct sw_flow *); +static void send_flow_expired(struct datapath *, struct sw_flow *, + enum ofp_flow_expired_reason); static void send_port_status(struct sw_port *p, uint8_t status); static void del_switch_port(struct sw_port *p); static void execute_actions(struct datapath *, struct buffer *, @@ -154,6 +158,7 @@ static void modify_th(struct buffer *buffer, uint16_t eth_proto, #define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS) +int run_flow_through_tables(struct datapath *, struct buffer *, int in_port); void fwd_port_input(struct datapath *, struct buffer *, int in_port); int fwd_control_input(struct datapath *, const struct sender *, const void *, size_t); @@ -187,7 +192,7 @@ dp_new(struct datapath **dp_, uint64_t dpid, struct rconn *rconn) return ENOMEM; } - dp->last_timeout = time(0); + dp->last_timeout = time_now(); list_init(&dp->remotes); dp->controller = remote_create(dp, rconn); dp->listen_vconn = NULL; @@ -200,8 +205,8 @@ dp_new(struct datapath **dp_, uint64_t dpid, struct rconn *rconn) } list_init(&dp->port_list); - dp->config.flags = 0; - dp->config.miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN); + dp->flags = 0; + dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; *dp_ = dp; return 0; } @@ -265,7 +270,7 @@ dp_add_listen_vconn(struct datapath *dp, struct vconn *listen_vconn) void dp_run(struct datapath *dp) { - time_t now = time(0); + time_t now = time_now(); struct sw_port *p, *pn; struct remote *r, *rn; struct buffer *buffer = NULL; @@ -276,7 +281,7 @@ dp_run(struct datapath *dp) chain_timeout(dp->chain, &deleted); LIST_FOR_EACH_SAFE (f, n, struct sw_flow, node, &deleted) { - send_flow_expired(dp, f); + send_flow_expired(dp, f, f->reason); list_remove(&f->node); flow_free(f); } @@ -546,18 +551,8 @@ dp_output_port(struct datapath *dp, struct buffer *buffer, } else if (out_port == OFPP_CONTROLLER) { dp_output_control(dp, buffer, in_port, 0, OFPR_ACTION); } else if (out_port == OFPP_TABLE) { - struct sw_flow_key key; - struct sw_flow *flow; - - key.wildcards = 0; - flow_extract(buffer, in_port, &key.flow); - flow = chain_lookup(dp->chain, &key); - if (flow != NULL) { - flow_used(flow, buffer); - execute_actions(dp, buffer, in_port, &key, - flow->actions, flow->n_actions); - } else { - buffer_delete(buffer); + if (run_flow_through_tables(dp, buffer, in_port)) { + buffer_delete(buffer); } } else { output_packet(dp, buffer, out_port); @@ -691,17 +686,20 @@ send_port_status(struct sw_port *p, uint8_t status) } void -send_flow_expired(struct datapath *dp, struct sw_flow *flow) +send_flow_expired(struct datapath *dp, struct sw_flow *flow, + enum ofp_flow_expired_reason reason) { struct buffer *buffer; struct ofp_flow_expired *ofe; ofe = make_openflow_xid(sizeof *ofe, OFPT_FLOW_EXPIRED, 0, &buffer); flow_fill_match(&ofe->match, &flow->key); - memset(ofe->pad, 0, sizeof ofe->pad); ofe->priority = htons(flow->priority); + ofe->reason = reason; + memset(ofe->pad, 0, sizeof ofe->pad); - ofe->duration = htonl(flow->timeout - flow->max_idle - flow->created); + ofe->duration = htonl(time_now() - flow->created); + memset(ofe->pad2, 0, sizeof ofe->pad2); ofe->packet_count = htonll(flow->packet_count); ofe->byte_count = htonll(flow->byte_count); send_openflow_buffer(dp, buffer, NULL); @@ -744,31 +742,53 @@ fill_flow_stats(struct buffer *buffer, struct sw_flow *flow, ofs->match.tp_src = flow->key.flow.tp_src; ofs->match.tp_dst = flow->key.flow.tp_dst; ofs->duration = htonl(now - flow->created); + ofs->priority = htons(flow->priority); + ofs->idle_timeout = htons(flow->idle_timeout); + ofs->hard_timeout = htons(flow->hard_timeout); + memset(ofs->pad2, 0, sizeof ofs->pad2); ofs->packet_count = htonll(flow->packet_count); ofs->byte_count = htonll(flow->byte_count); - ofs->priority = htons(flow->priority); - ofs->max_idle = htons(flow->max_idle); memcpy(ofs->actions, flow->actions, sizeof *ofs->actions * flow->n_actions); } /* 'buffer' was received on 'in_port', a physical switch port between 0 and - * OFPP_MAX. Process it according to 'chain'. */ -void fwd_port_input(struct datapath *dp, struct buffer *buffer, int in_port) + * OFPP_MAX. Process it according to 'dp''s flow table. Returns 0 if + * successful, in which case 'buffer' is destroyed, or -ESRCH if there is no + * matching flow, in which case 'buffer' still belongs to the caller. */ +int run_flow_through_tables(struct datapath *dp, struct buffer *buffer, + int in_port) { struct sw_flow_key key; struct sw_flow *flow; key.wildcards = 0; - flow_extract(buffer, in_port, &key.flow); + if (flow_extract(buffer, in_port, &key.flow) + && (dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { + /* Drop fragment. */ + buffer_delete(buffer); + return 0; + } + flow = chain_lookup(dp->chain, &key); if (flow != NULL) { flow_used(flow, buffer); execute_actions(dp, buffer, in_port, &key, flow->actions, flow->n_actions); + return 0; } else { - dp_output_control(dp, buffer, in_port, ntohs(dp->config.miss_send_len), + return -ESRCH; + } +} + +/* 'buffer' was received on 'in_port', a physical switch port between 0 and + * OFPP_MAX. Process it according to 'dp''s flow table, sending it up to the + * controller if no flow matches. Takes ownership of 'buffer'. */ +void fwd_port_input(struct datapath *dp, struct buffer *buffer, int in_port) +{ + if (run_flow_through_tables(dp, buffer, in_port)) { + dp_output_control(dp, buffer, in_port, dp->miss_send_len, OFPR_NO_MATCH); } } @@ -959,10 +979,8 @@ recv_get_config_request(struct datapath *dp, const struct sender *sender, osc = make_openflow_reply(sizeof *osc, OFPT_GET_CONFIG_REPLY, sender, &buffer); - assert(sizeof *osc == sizeof dp->config); - memcpy(((char *)osc) + sizeof osc->header, - ((char *)&dp->config) + sizeof dp->config.header, - sizeof dp->config - sizeof dp->config.header); + osc->flags = htons(dp->flags); + osc->miss_send_len = htons(dp->miss_send_len); return send_openflow_buffer(dp, buffer, sender); } @@ -972,7 +990,15 @@ recv_set_config(struct datapath *dp, const struct sender *sender UNUSED, const void *msg) { const struct ofp_switch_config *osc = msg; - dp->config = *osc; + int flags; + + flags = ntohs(osc->flags) & (OFPC_SEND_FLOW_EXP | OFPC_FRAG_MASK); + if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL + && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) { + flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP; + } + dp->flags = flags; + dp->miss_send_len = ntohs(osc->miss_send_len); return 0; } @@ -1050,11 +1076,11 @@ add_flow(struct datapath *dp, const struct ofp_flow_mod *ofm) /* Fill out flow. */ flow_extract_match(&flow->key, &ofm->match); - flow->max_idle = ntohs(ofm->max_idle); flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1; - flow->timeout = time(0) + flow->max_idle; /* FIXME */ + flow->idle_timeout = ntohs(ofm->idle_timeout); + flow->hard_timeout = ntohs(ofm->hard_timeout); + flow->used = flow->created = time_now(); flow->n_actions = n_acts; - flow->created = time(0); /* FIXME */ flow->byte_count = 0; flow->packet_count = 0; memcpy(flow->actions, ofm->actions, n_acts * sizeof *flow->actions); @@ -1149,7 +1175,7 @@ static int flow_stats_dump(struct datapath *dp, void *state, flow_extract_match(&match_key, &s->rq.match); s->buffer = buffer; - s->now = time(0); + s->now = time_now(); while (s->table_idx < dp->chain->n_tables && (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx)) { @@ -1560,7 +1586,7 @@ uint32_t save_buffer(struct buffer *buffer) if (p->buffer) { /* Don't buffer packet if existing entry is less than * OVERWRITE_SECS old. */ - if (time(0) < p->timeout) { /* FIXME */ + if (time_now() < p->timeout) { /* FIXME */ return -1; } else { buffer_delete(p->buffer); @@ -1571,7 +1597,7 @@ uint32_t save_buffer(struct buffer *buffer) if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) p->cookie = 0; p->buffer = buffer_clone(buffer); /* FIXME */ - p->timeout = time(0) + OVERWRITE_SECS; /* FIXME */ + p->timeout = time_now() + OVERWRITE_SECS; /* FIXME */ id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); return id;