X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fforward.c;h=bfc5815223fca387dbecf806ba91320039ee5cf6;hb=db74f018735cef6f5e975e6278f78997d1de23b3;hp=a2b6691f1bff8f6be13eee9d46c7ffea6784f749;hpb=60a87c9b0032346568485ad40fd72ea1f72b8674;p=sliver-openvswitch.git diff --git a/datapath/forward.c b/datapath/forward.c index a2b6691f1..bfc581522 100644 --- a/datapath/forward.c +++ b/datapath/forward.c @@ -21,9 +21,6 @@ /* FIXME: do we need to use GFP_ATOMIC everywhere here? */ -static void execute_actions(struct datapath *, struct sk_buff *, - const struct sw_flow_key *, - const struct ofp_action *, int n_actions); static int make_writable(struct sk_buff **); static struct sk_buff *retrieve_skb(uint32_t id); @@ -44,7 +41,7 @@ void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, int in_port) flow->actions, flow->n_actions); } else { dp_output_control(chain->dp, skb, fwd_save_skb(skb), - chain->dp->config.miss_send_len, + chain->dp->miss_send_len, OFPR_NO_MATCH); } } @@ -60,7 +57,7 @@ static int do_output(struct datapath *dp, struct sk_buff *skb, size_t max_len, max_len, OFPR_ACTION)); } -static void execute_actions(struct datapath *dp, struct sk_buff *skb, +void execute_actions(struct datapath *dp, struct sk_buff *skb, const struct sw_flow_key *key, const struct ofp_action *actions, int n_actions) { @@ -260,29 +257,34 @@ struct sk_buff *execute_setter(struct sk_buff *skb, uint16_t eth_proto, } static int -recv_features_request(struct sw_chain *chain, const void *msg) +recv_features_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) { - const struct ofp_header *ofr = msg; - return dp_send_features_reply(chain->dp, ofr->xid); + return dp_send_features_reply(chain->dp, sender); } static int -recv_get_config_request(struct sw_chain *chain, const void *msg) +recv_get_config_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) { - const struct ofp_header *ofr = msg; - return dp_send_config_reply(chain->dp, ofr->xid); + return dp_send_config_reply(chain->dp, sender); } static int -recv_set_config(struct sw_chain *chain, const void *msg) +recv_set_config(struct sw_chain *chain, const struct sender *sender, + const void *msg) { const struct ofp_switch_config *osc = msg; - chain->dp->config = *osc; + + chain->dp->flags = ntohs(osc->flags); + chain->dp->miss_send_len = ntohs(osc->miss_send_len); + return 0; } static int -recv_packet_out(struct sw_chain *chain, const void *msg) +recv_packet_out(struct sw_chain *chain, const struct sender *sender, + const void *msg) { const struct ofp_packet_out *opo = msg; struct sk_buff *skb; @@ -330,7 +332,8 @@ recv_packet_out(struct sw_chain *chain, const void *msg) } static int -recv_port_mod(struct sw_chain *chain, const void *msg) +recv_port_mod(struct sw_chain *chain, const struct sender *sender, + const void *msg) { const struct ofp_port_mod *opm = msg; @@ -343,6 +346,7 @@ static int add_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm) { int error = -ENOMEM; + int i; int n_acts; struct sw_flow *flow; @@ -354,6 +358,19 @@ add_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm) goto error; } + /* To prevent loops, make sure there's no action to send to the + * OFP_TABLE virtual port. + */ + for (i=0; iactions[i]; + + if (a->type == htons(OFPAT_OUTPUT) + && a->arg.output.port == htons(OFPP_TABLE)) { + /* xxx Send fancy new error message? */ + goto error; + } + } + /* Allocate memory. */ flow = flow_alloc(n_acts, GFP_ATOMIC); if (flow == NULL) @@ -363,6 +380,7 @@ add_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm) flow_extract_match(&flow->key, &ofm->match); flow->group_id = ntohl(ofm->group_id); flow->max_idle = ntohs(ofm->max_idle); + flow->priority = ntohs(ofm->priority); flow->timeout = jiffies + flow->max_idle * HZ; flow->n_actions = n_acts; flow->init_time = jiffies; @@ -400,7 +418,7 @@ error: } static int -recv_flow(struct sw_chain *chain, const void *msg) +recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg) { const struct ofp_flow_mod *ofm = msg; uint16_t command = ntohs(ofm->command); @@ -420,15 +438,31 @@ recv_flow(struct sw_chain *chain, const void *msg) } } -/* 'msg', which is 'length' bytes long, was received from the control path. - * Apply it to 'chain'. */ +static int +recv_port_stats_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_port_stats(chain->dp, sender); +} + +static int +recv_table_stats_request(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + return dp_send_table_stats(chain->dp, sender); +} + +/* 'msg', which is 'length' bytes long, was received across Netlink from + * 'sender'. Apply it to 'chain'. */ int -fwd_control_input(struct sw_chain *chain, const void *msg, size_t length) +fwd_control_input(struct sw_chain *chain, const struct sender *sender, + const void *msg, size_t length) { struct openflow_packet { size_t min_size; - int (*handler)(struct sw_chain *, const void *); + int (*handler)(struct sw_chain *, const struct sender *, + const void *); }; static const struct openflow_packet packets[] = { @@ -456,16 +490,21 @@ fwd_control_input(struct sw_chain *chain, const void *msg, size_t length) sizeof (struct ofp_port_mod), recv_port_mod, }, + [OFPT_PORT_STATS_REQUEST] = { + sizeof (struct ofp_port_stats_request), + recv_port_stats_request, + }, + [OFPT_TABLE_STATS_REQUEST] = { + sizeof (struct ofp_table_stats_request), + recv_table_stats_request, + }, }; const struct openflow_packet *pkt; struct ofp_header *oh; - if (length < sizeof(struct ofp_header)) - return -EINVAL; - oh = (struct ofp_header *) msg; - if (oh->version != 1 || oh->type >= ARRAY_SIZE(packets) + if (oh->version != OFP_VERSION || oh->type >= ARRAY_SIZE(packets) || ntohs(oh->length) > length) return -EINVAL; @@ -475,7 +514,7 @@ fwd_control_input(struct sw_chain *chain, const void *msg, size_t length) if (length < pkt->min_size) return -EFAULT; - return pkt->handler(chain, msg); + return pkt->handler(chain, sender, msg); } /* Packet buffering. */