datapath: add skb mark matching and set action
[openvswitch] / lib / match.c
index 69129d4f2abc1cf145d57cc803371693e3650ec4..29ee1535e0cbde3e0d66fd146f284bbe95e32b58 100644 (file)
 #include "byte-order.h"
 #include "dynamic-string.h"
 #include "packets.h"
+#include "vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(match);
+
 
 /* Converts the flow in 'flow' into a match in 'match', with the given
  * 'wildcards'. */
@@ -33,12 +37,97 @@ match_init(struct match *match,
     match_zero_wildcarded_fields(match);
 }
 
+/* Converts a flow into a match.  It sets the wildcard masks based on
+ * the packet contents.  It will not set the mask for fields that do not
+ * make sense for the packet type. */
+void
+match_wc_init(struct match *match, const struct flow *flow)
+{
+    struct flow_wildcards *wc;
+    int i;
+
+    match->flow = *flow;
+    wc = &match->wc;
+    memset(&wc->masks, 0x0, sizeof wc->masks);
+
+    memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+
+    if (flow->nw_proto) {
+        memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+    }
+
+    for (i = 0; i < FLOW_N_REGS; i++) {
+        if (flow->regs[i]) {
+            memset(&wc->masks.regs[i], 0xff, sizeof wc->masks.regs[i]);
+        }
+    }
+
+    if (flow->tunnel.ip_dst || flow->tunnel.tun_id) {
+        memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
+        memset(&wc->masks.tunnel.ip_src, 0xff, sizeof wc->masks.tunnel.ip_src);
+        memset(&wc->masks.tunnel.ip_dst, 0xff, sizeof wc->masks.tunnel.ip_dst);
+        memset(&wc->masks.tunnel.flags, 0xff, sizeof wc->masks.tunnel.flags);
+        memset(&wc->masks.tunnel.ip_tos, 0xff, sizeof wc->masks.tunnel.ip_tos);
+        memset(&wc->masks.tunnel.ip_ttl, 0xff, sizeof wc->masks.tunnel.ip_ttl);
+    }
+    memset(&wc->masks.metadata, 0xff, sizeof wc->masks.metadata);
+    memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
+    memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
+    memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
+    memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+
+    if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+        memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src);
+        memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
+        memset(&wc->masks.ipv6_label, 0xff, sizeof wc->masks.ipv6_label);
+    } else if (flow->dl_type == htons(ETH_TYPE_IP) ||
+               (flow->dl_type == htons(ETH_TYPE_ARP)) ||
+               (flow->dl_type == htons(ETH_TYPE_RARP))) {
+        memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
+        memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
+    }
+
+    if (flow->dl_type == htons(ETH_TYPE_ARP) ||
+        flow->dl_type == htons(ETH_TYPE_RARP)) {
+        memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
+        memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha);
+    }
+
+    if (flow->dl_type == htons(ETH_TYPE_IPV6) ||
+        flow->dl_type == htons(ETH_TYPE_IP)) {
+        memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos);
+        memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl);
+    }
+
+    if (flow->nw_frag) {
+        memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag);
+    }
+
+    if (flow->nw_proto == IPPROTO_ICMP || flow->nw_proto == IPPROTO_ICMPV6 ||
+        (flow->tp_src || flow->tp_dst)) {
+        memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
+        memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+    }
+
+    if (flow->nw_proto == IPPROTO_ICMPV6) {
+        memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
+        memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha);
+    }
+
+    return;
+}
+
 /* Converts the flow in 'flow' into an exact-match match in 'match'. */
 void
 match_init_exact(struct match *match, const struct flow *flow)
 {
+    ovs_be64 tun_id = flow->tunnel.tun_id;
+
     match->flow = *flow;
     match->flow.skb_priority = 0;
+    match->flow.skb_mark = 0;
+    memset(&match->flow.tunnel, 0, sizeof match->flow.tunnel);
+    match->flow.tunnel.tun_id = tun_id;
     flow_wildcards_init_exact(&match->wc);
 }
 
@@ -102,8 +191,8 @@ match_set_tun_id(struct match *match, ovs_be64 tun_id)
 void
 match_set_tun_id_masked(struct match *match, ovs_be64 tun_id, ovs_be64 mask)
 {
-    match->wc.masks.tun_id = mask;
-    match->flow.tun_id = tun_id & mask;
+    match->wc.masks.tunnel.tun_id = mask;
+    match->flow.tunnel.tun_id = tun_id & mask;
 }
 
 void
@@ -567,7 +656,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
 
     if (priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%u,", priority);
@@ -609,6 +698,8 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
             }
         } else if (f->dl_type == htons(ETH_TYPE_ARP)) {
             ds_put_cstr(s, "arp,");
+        } else if (f->dl_type == htons(ETH_TYPE_RARP)) {
+            ds_put_cstr(s, "rarp,");
         } else {
             skip_type = false;
         }
@@ -626,15 +717,16 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
             break;
         }
     }
-    switch (wc->masks.tun_id) {
+    switch (wc->masks.tunnel.tun_id) {
     case 0:
         break;
     case CONSTANT_HTONLL(UINT64_MAX):
-        ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tun_id));
+        ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tunnel.tun_id));
         break;
     default:
         ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
-                      ntohll(f->tun_id), ntohll(wc->masks.tun_id));
+                      ntohll(f->tunnel.tun_id),
+                      ntohll(wc->masks.tunnel.tun_id));
         break;
     }
     switch (wc->masks.metadata) {
@@ -693,18 +785,24 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
                               ntohl(wc->masks.ipv6_label));
             }
         }
+    } else if (f->dl_type == htons(ETH_TYPE_ARP) ||
+               f->dl_type == htons(ETH_TYPE_RARP)) {
+        format_ip_netmask(s, "arp_spa", f->nw_src, wc->masks.nw_src);
+        format_ip_netmask(s, "arp_tpa", f->nw_dst, wc->masks.nw_dst);
     } else {
         format_ip_netmask(s, "nw_src", f->nw_src, wc->masks.nw_src);
         format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst);
     }
     if (!skip_proto && wc->masks.nw_proto) {
-        if (f->dl_type == htons(ETH_TYPE_ARP)) {
+        if (f->dl_type == htons(ETH_TYPE_ARP) ||
+            f->dl_type == htons(ETH_TYPE_RARP)) {
             ds_put_format(s, "arp_op=%"PRIu8",", f->nw_proto);
         } else {
             ds_put_format(s, "nw_proto=%"PRIu8",", f->nw_proto);
         }
     }
-    if (f->dl_type == htons(ETH_TYPE_ARP)) {
+    if (f->dl_type == htons(ETH_TYPE_ARP) ||
+        f->dl_type == htons(ETH_TYPE_RARP)) {
         format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha);
         format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha);
     }
@@ -735,10 +833,12 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
                       f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "not_later");
         break;
     }
-    if (f->nw_proto == IPPROTO_ICMP) {
+    if (f->dl_type == htons(ETH_TYPE_IP) &&
+        f->nw_proto == IPPROTO_ICMP) {
         format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
         format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
-    } else if (f->nw_proto == IPPROTO_ICMPV6) {
+    } else if (f->dl_type == htons(ETH_TYPE_IPV6) &&
+               f->nw_proto == IPPROTO_ICMPV6) {
         format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
         format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
         format_ipv6_netmask(s, "nd_target", &f->nd_target,