Implement OFPC_FRAG_DROP fragment handling policy.
authorBen Pfaff <blp@nicira.com>
Mon, 4 Aug 2008 22:34:26 +0000 (15:34 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 7 Aug 2008 17:34:37 +0000 (10:34 -0700)
datapath/flow.c
datapath/flow.h
datapath/forward.c
include/flow.h
include/openflow.h
lib/flow.c
switch/datapath.c

index c49a4cb..094d32b 100644 (file)
@@ -211,12 +211,14 @@ static int udphdr_ok(struct sk_buff *skb)
 }
 
 /* Parses the Ethernet frame in 'skb', which was received on 'in_port',
- * and initializes 'key' to match. */
-void flow_extract(struct sk_buff *skb, uint16_t in_port,
-                 struct sw_flow_key *key)
+ * and initializes 'key' to match.  Returns 1 if 'skb' contains an IP
+ * fragment, 0 otherwise. */
+int flow_extract(struct sk_buff *skb, uint16_t in_port,
+                struct sw_flow_key *key)
 {
        struct ethhdr *mac;
        int nh_ofs, th_ofs;
+       int retval = 0;
 
        key->in_port = htons(in_port);
        key->wildcards = 0;
@@ -292,10 +294,11 @@ void flow_extract(struct sk_buff *skb, uint16_t in_port,
                                }
                        }
                } else {
+                       retval = 1;
                        goto no_th;
                }
 
-               return;
+               return 0;
        }
 
        key->nw_src = 0;
@@ -307,6 +310,7 @@ no_proto:
 no_th:
        key->tp_src = 0;
        key->tp_dst = 0;
+       return retval;
 }
 
 /* Initializes the flow module.
index e964c71..28c2b8b 100644 (file)
@@ -83,7 +83,7 @@ int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *,
 struct sw_flow *flow_alloc(int n_actions, gfp_t flags);
 void flow_free(struct sw_flow *);
 void flow_deferred_free(struct sw_flow *);
-void flow_extract(struct sk_buff *, uint16_t in_port, struct sw_flow_key *);
+int flow_extract(struct sk_buff *, uint16_t in_port, struct sw_flow_key *);
 void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from);
 void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from);
 
index 8e2bc11..4dee840 100644 (file)
@@ -36,7 +36,13 @@ int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb,
        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);
index d1043d2..57754c1 100644 (file)
@@ -57,7 +57,7 @@ struct flow {
 };
 BUILD_ASSERT_DECL(sizeof (struct flow) == 32);
 
-void flow_extract(struct buffer *, uint16_t in_port, struct flow *);
+int flow_extract(struct buffer *, uint16_t in_port, struct flow *);
 void flow_print(FILE *, const struct flow *);
 int flow_compare(const struct flow *, const struct flow *);
 unsigned long int flow_hash(const struct flow *, uint32_t basis);
index 238c571..9db427b 100644 (file)
@@ -132,7 +132,13 @@ OFP_ASSERT(sizeof(struct ofp_header) == 8);
 
 enum ofp_config_flags {
     /* Tells datapath to notify the controller of expired flow entries. */
-    OFPC_SEND_FLOW_EXP = 1 << 0
+    OFPC_SEND_FLOW_EXP = 1 << 0,
+
+    /* Handling of IP fragments. */
+    OFPC_FRAG_NORMAL = 0 << 1,  /* No special handling for fragments. */
+    OFPC_FRAG_DROP = 1 << 1,    /* Drop fragments. */
+    OFPC_FRAG_REASM = 2 << 1,   /* Reassemble (only if OFPC_IP_REASM set). */
+    OFPC_FRAG_MASK = 3 << 1
 };
 
 /* Switch configuration. */
@@ -150,8 +156,9 @@ enum ofp_capabilities {
     OFPC_TABLE_STATS  = 1 << 1, /* Table statistics. */
     OFPC_PORT_STATS   = 1 << 2, /* Port statistics. */
     OFPC_STP          = 1 << 3, /* 802.11d spanning tree. */
-    OFPC_MULTI_PHY_TX = 1 << 4  /* Supports transmitting through multiple
+    OFPC_MULTI_PHY_TX = 1 << 4, /* Supports transmitting through multiple
                                    physical interfaces */
+    OFPC_IP_REASM     = 1 << 5  /* Can reassemble IP fragments. */
 };
 
 /* Flags to indicate behavior of the physical port */
index 7a943d7..f534f57 100644 (file)
@@ -88,11 +88,13 @@ pull_vlan(struct buffer *packet)
     return buffer_try_pull(packet, VLAN_HEADER_LEN);
 }
 
-void
+/* Returns 1 if 'packet' is an IP fragment, 0 otherwise. */
+int
 flow_extract(struct buffer *packet, uint16_t in_port, struct flow *flow)
 {
     struct buffer b = *packet;
     struct eth_header *eth;
+    int retval = 0;
 
     if (b.size < ETH_TOTAL_MIN) {
         /* This message is not too useful since there are various ways that we
@@ -121,7 +123,7 @@ flow_extract(struct buffer *packet, uint16_t in_port, struct flow *flow)
             /* This is an 802.2 frame */
             struct llc_snap_header *h = buffer_at(&b, 0, sizeof *h);
             if (h == NULL) {
-                return;
+                return 0;
             }
             if (h->llc.llc_dsap == LLC_DSAP_SNAP
                 && h->llc.llc_ssap == LLC_SSAP_SNAP
@@ -179,10 +181,13 @@ flow_extract(struct buffer *packet, uint16_t in_port, struct flow *flow)
                             flow->nw_proto = 0;
                         }
                     }
+                } else {
+                    retval = 1;
                 }
             }
         }
     }
+    return retval;
 }
 
 void
index 15cca50..4391634 100644 (file)
@@ -757,7 +757,13 @@ int run_flow_through_tables(struct datapath *dp, struct buffer *buffer,
     struct sw_flow *flow;
 
     key.wildcards = 0;
-    flow_extract(buffer, in_port, &key.flow);
+    if (flow_extract(buffer, in_port, &key.flow)
+        && (dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) {
+        /* Drop fragment. */
+        buffer_delete(buffer);
+        return 0;
+    }
+
     flow = chain_lookup(dp->chain, &key);
     if (flow != NULL) {
         flow_used(flow, buffer);