Make sure that do_port_input() always puts a MAC header on packets.
[sliver-openvswitch.git] / datapath / forward.c
index 9bbb030..b3c2f7a 100644 (file)
@@ -12,7 +12,9 @@
 #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"
 
@@ -222,7 +224,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 +240,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) {
@@ -246,6 +252,7 @@ add_flow(struct sw_chain *chain, const struct sender *sender,
                if (skb) {
                        struct sw_flow_key key;
                        flow_used(flow, skb);
+                       dp_set_origin(chain->dp, ntohs(ofm->match.in_port), skb);
                        flow_extract(skb, ntohs(ofm->match.in_port), &key);
                        execute_actions(chain->dp, skb, &key, ofm->actions, actions_len, 0);
                }
@@ -332,6 +339,25 @@ recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg)
        }
 }
 
+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
@@ -350,6 +376,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,
@@ -373,15 +411,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;
@@ -398,8 +428,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];
@@ -527,4 +561,3 @@ void fwd_exit(void)
 {
        fwd_discard_all();
 }
-