}
/* 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;
}
}
} else {
+ retval = 1;
goto no_th;
}
- return;
+ return 0;
}
key->nw_src = 0;
no_th:
key->tp_src = 0;
key->tp_dst = 0;
+ return retval;
}
/* Initializes the flow module.
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);
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);
};
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);
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. */
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 */
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
/* 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
flow->nw_proto = 0;
}
}
+ } else {
+ retval = 1;
}
}
}
}
+ return retval;
}
void
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);