#include <linux/types.h>
#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"
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,
{
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);
/* 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)
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. */
/* 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) {
} 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
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,
[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;
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];
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];
* 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;
}
}
* 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);
{
fwd_discard_all();
}
-