#include <linux/module.h>
#include <linux/tcp.h>
#include <linux/udp.h>
+#include <linux/icmp.h>
#include <linux/in.h>
#include <linux/rcupdate.h>
#include <net/ip.h>
* network protocol is unknown. */
to->wildcards |= OFPFW_TP;
} else if (from->nw_proto == IPPROTO_TCP
- || from->nw_proto == IPPROTO_UDP) {
+ || from->nw_proto == IPPROTO_UDP
+ || from->nw_proto == IPPROTO_ICMP) {
to->tp_src = from->tp_src;
to->tp_dst = from->tp_dst;
} else {
}
EXPORT_SYMBOL(flow_timeout);
+/* Returns nonzero if 'flow' contains an output action to 'out_port' or
+ * has the value OFPP_NONE. 'out_port' is in network-byte order. */
+int flow_has_out_port(struct sw_flow *flow, uint16_t out_port)
+{
+ struct sw_flow_actions *sf_acts;
+ size_t actions_len;
+ uint8_t *p;
+
+ if (out_port == htons(OFPP_NONE))
+ return 1;
+
+ sf_acts = rcu_dereference(flow->sf_acts);
+
+ actions_len = sf_acts->actions_len;
+ p = (uint8_t *)sf_acts->actions;
+
+ while (actions_len > 0) {
+ struct ofp_action_header *ah = (struct ofp_action_header *)p;
+ size_t len = ntohs(ah->len);
+
+ if (ah->type == htons(OFPAT_OUTPUT)) {
+ struct ofp_action_output *oa = (struct ofp_action_output *)p;
+ if (oa->port == out_port)
+ return 1;
+ }
+
+ p += len;
+ actions_len -= len;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(flow_has_out_port);
+
/* Allocates and returns a new flow with room for 'actions_len' actions,
* using allocation flags 'flags'. Returns the new flow or a null pointer
* on failure. */
return pskb_may_pull(skb, th_ofs + sizeof(struct udphdr));
}
+static int icmphdr_ok(struct sk_buff *skb)
+{
+ int th_ofs = skb_transport_offset(skb);
+ return pskb_may_pull(skb, th_ofs + sizeof(struct icmphdr));
+}
+
/* Parses the Ethernet frame in 'skb', which was received on 'in_port',
* and initializes 'key' to match. Returns 1 if 'skb' contains an IP
* fragment, 0 otherwise. */
* header. */
key->nw_proto = 0;
}
+ } else if (key->nw_proto == IPPROTO_ICMP) {
+ if (icmphdr_ok(skb)) {
+ struct icmphdr *icmp = icmp_hdr(skb);
+ /* The ICMP type and code fields use the 16-bit
+ * transport port fields, so we need to store them
+ * in 16-bit network byte order. */
+ key->icmp_type = htons(icmp->type);
+ key->icmp_code = htons(icmp->code);
+ } else {
+ /* Avoid tricking other code into
+ * thinking that this packet has an L4
+ * header. */
+ key->nw_proto = 0;
+ }
}
} else {
retval = 1;