X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fforward.c;h=d54674ac8349d135571ac98ca19dbb542a50656a;hb=62093bae13aa604a6e542ce327a3954d45760883;hp=48bec7caebbccf6db1a89da3e3b113c1d1f82699;hpb=dece4bacae29e94c41430fb5dcdf6cbe5290b2b8;p=sliver-openvswitch.git diff --git a/datapath/forward.c b/datapath/forward.c index 48bec7cae..d54674ac8 100644 --- a/datapath/forward.c +++ b/datapath/forward.c @@ -12,7 +12,9 @@ #include #include "forward.h" #include "datapath.h" +#include "openflow/nicira-ext.h" #include "dp_act.h" +#include "nx_msg.h" #include "chain.h" #include "flow.h" @@ -66,6 +68,8 @@ int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb, void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, struct net_bridge_port *p) { + WARN_ON_ONCE(skb_shared(skb)); + WARN_ON_ONCE(skb->destructor); if (run_flow_through_tables(chain, skb, p)) dp_output_control(chain->dp, skb, fwd_save_skb(skb), chain->dp->miss_send_len, @@ -118,8 +122,6 @@ recv_packet_out(struct sw_chain *chain, const struct sender *sender, { const struct ofp_packet_out *opo = msg; struct sk_buff *skb; - struct vlan_ethhdr *mac; - int nh_ofs; uint16_t v_code; struct sw_flow_key key; size_t actions_len = ntohs(opo->actions_len); @@ -141,16 +143,11 @@ recv_packet_out(struct sw_chain *chain, const struct sender *sender, /* FIXME? We don't reserve NET_IP_ALIGN or NET_SKB_PAD since * we're just transmitting this raw without examining anything * at those layers. */ - memcpy(skb_put(skb, data_len), (uint8_t *)opo->actions + actions_len, - data_len); - - skb_set_mac_header(skb, 0); - mac = vlan_eth_hdr(skb); - if (likely(mac->h_vlan_proto != htons(ETH_P_8021Q))) - nh_ofs = sizeof(struct ethhdr); - else - nh_ofs = sizeof(struct vlan_ethhdr); - skb_set_network_header(skb, nh_ofs); + skb_put(skb, data_len); + skb_copy_to_linear_data(skb, + (uint8_t *)opo->actions + actions_len, + data_len); + skb_reset_mac_header(skb); } else { skb = retrieve_skb(ntohl(opo->buffer_id)); if (!skb) @@ -222,7 +219,7 @@ add_flow(struct sw_chain *chain, const struct sender *sender, if (v_code != ACT_VALIDATION_OK) { dp_send_error_msg(chain->dp, sender, OFPET_BAD_ACTION, v_code, ofm, ntohs(ofm->header.length)); - goto error; + goto error_free_flow; } /* Fill out flow. */ @@ -238,7 +235,11 @@ add_flow(struct sw_chain *chain, const struct sender *sender, /* Act. */ error = chain_insert(chain, flow); - if (error) + if (error == -ENOBUFS) { + dp_send_error_msg(chain->dp, sender, OFPET_FLOW_MOD_FAILED, + OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length)); + goto error_free_flow; + } else if (error) goto error_free_flow; error = 0; if (ntohl(ofm->buffer_id) != (uint32_t) -1) { @@ -321,18 +322,38 @@ recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg) } else if (command == OFPFC_DELETE) { struct sw_flow_key key; flow_extract_match(&key, &ofm->match); - return chain_delete(chain, &key, 0, 0) ? 0 : -ESRCH; + return chain_delete(chain, &key, ofm->out_port, 0, 0) ? 0 : -ESRCH; } else if (command == OFPFC_DELETE_STRICT) { struct sw_flow_key key; uint16_t priority; flow_extract_match(&key, &ofm->match); priority = key.wildcards ? ntohs(ofm->priority) : -1; - return chain_delete(chain, &key, priority, 1) ? 0 : -ESRCH; + return chain_delete(chain, &key, ofm->out_port, + priority, 1) ? 0 : -ESRCH; } else { return -ENOTSUPP; } } +static int +recv_vendor(struct sw_chain *chain, const struct sender *sender, + const void *msg) +{ + const struct ofp_vendor_header *ovh = msg; + + switch(ntohl(ovh->vendor)) + { + case NX_VENDOR_ID: + return nx_recv_msg(chain, sender, msg); + default: + if (net_ratelimit()) + printk("Uknown vendor: %#x\n", ntohl(ovh->vendor)); + dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, + OFPBRC_BAD_VENDOR, msg, ntohs(ovh->header.length)); + return -EINVAL; + } +} + /* 'msg', which is 'length' bytes long, was received across Netlink from * 'sender'. Apply it to 'chain'. */ int @@ -351,6 +372,18 @@ fwd_control_input(struct sw_chain *chain, const struct sender *sender, sizeof (struct ofp_header), recv_hello, }, + [OFPT_ECHO_REQUEST] = { + sizeof (struct ofp_header), + recv_echo_request, + }, + [OFPT_ECHO_REPLY] = { + sizeof (struct ofp_header), + recv_echo_reply, + }, + [OFPT_VENDOR] = { + sizeof (struct ofp_vendor_header), + recv_vendor, + }, [OFPT_FEATURES_REQUEST] = { sizeof (struct ofp_header), recv_features_request, @@ -374,15 +407,7 @@ fwd_control_input(struct sw_chain *chain, const struct sender *sender, [OFPT_PORT_MOD] = { sizeof (struct ofp_port_mod), recv_port_mod, - }, - [OFPT_ECHO_REQUEST] = { - sizeof (struct ofp_header), - recv_echo_request, - }, - [OFPT_ECHO_REPLY] = { - sizeof (struct ofp_header), - recv_echo_reply, - }, + } }; struct ofp_header *oh; @@ -399,8 +424,12 @@ fwd_control_input(struct sw_chain *chain, const struct sender *sender, OFPBRC_BAD_VERSION, msg, length); return -EINVAL; } - if (ntohs(oh->length) > length) + if (ntohs(oh->length) != length) { + if (net_ratelimit()) + printk("received message length wrong: %d/%d\n", + ntohs(oh->length), length); return -EINVAL; + } if (oh->type < ARRAY_SIZE(packets)) { const struct openflow_packet *pkt = &packets[oh->type]; @@ -437,6 +466,11 @@ uint32_t fwd_save_skb(struct sk_buff *skb) unsigned long int flags; uint32_t id; + /* FIXME: Probably just need a skb_clone() here. */ + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) + return -1; + spin_lock_irqsave(&buffer_lock, flags); buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK; p = &buffers[buffer_idx]; @@ -445,9 +479,13 @@ uint32_t fwd_save_skb(struct sk_buff *skb) * OVERWRITE_SECS old. */ if (time_before(jiffies, p->exp_jiffies)) { spin_unlock_irqrestore(&buffer_lock, flags); + kfree_skb(skb); return -1; } else { - /* Defer kfree_skb() until interrupts re-enabled. */ + /* Defer kfree_skb() until interrupts re-enabled. + * FIXME: we only need to do that if it has a + * destructor, but it never should since we orphan + * sk_buffs on entry. */ old_skb = p->skb; } } @@ -455,7 +493,6 @@ uint32_t fwd_save_skb(struct sk_buff *skb) * special. */ if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1) p->cookie = 0; - skb_get(skb); p->skb = skb; p->exp_jiffies = jiffies + OVERWRITE_JIFFIES; id = buffer_idx | (p->cookie << PKT_BUFFER_BITS); @@ -528,4 +565,3 @@ void fwd_exit(void) { fwd_discard_all(); } -