Implement OFPC_FRAG_DROP fragment handling policy.
[sliver-openvswitch.git] / datapath / forward.c
index c8df1a0..4dee840 100644 (file)
@@ -27,23 +27,42 @@ static struct sk_buff *retrieve_skb(uint32_t id);
 static void discard_skb(uint32_t id);
 
 /* 'skb' was received on 'in_port', a physical switch port between 0 and
- * OFPP_MAX.  Process it according to 'chain'. */
-void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, int in_port)
+ * OFPP_MAX.  Process it according to 'chain'.  Returns 0 if successful, in
+ * which case 'skb' is destroyed, or -ESRCH if there is no matching flow, in
+ * which case 'skb' still belongs to the caller. */
+int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb,
+                           int in_port)
 {
        struct sw_flow_key key;
        struct sw_flow *flow;
 
-       flow_extract(skb, in_port, &key);
+       if (flow_extract(skb, in_port, &key)
+           && (chain->dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) {
+               /* Drop fragment. */
+               kfree_skb(skb);
+               return 0;
+       }
+
        flow = chain_lookup(chain, &key);
        if (likely(flow != NULL)) {
                flow_used(flow, skb);
                execute_actions(chain->dp, skb, &key,
                                flow->actions, flow->n_actions);
+               return 0;
        } else {
+               return -ESRCH;
+       }
+}
+
+/* 'skb' was received on 'in_port', a physical switch port between 0 and
+ * OFPP_MAX.  Process it according to 'chain', sending it up to the controller
+ * if no flow matches.  Takes ownership of 'skb'. */
+void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, int in_port)
+{
+       if (run_flow_through_tables(chain, skb, in_port))
                dp_output_control(chain->dp, skb, fwd_save_skb(skb), 
                                  chain->dp->miss_send_len,
                                  OFPR_NO_MATCH);
-       }
 }
 
 static int do_output(struct datapath *dp, struct sk_buff *skb, size_t max_len,