Remove encal_dl_type from struct flow
[sliver-openvswitch.git] / lib / match.c
index e53a11a..2aa4e89 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <config.h>
 #include "match.h"
-#include <assert.h>
 #include <stdlib.h>
 #include "byte-order.h"
 #include "dynamic-string.h"
+#include "ofp-util.h"
 #include "packets.h"
 #include "vlog.h"
 
@@ -56,20 +56,33 @@ match_wc_init(struct match *match, const struct flow *flow)
         memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
     }
 
+    if (flow->skb_priority) {
+        memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority);
+    }
+
+    if (flow->skb_mark) {
+        memset(&wc->masks.skb_mark, 0xff, sizeof wc->masks.skb_mark);
+    }
+
     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);
+    if (flow->tunnel.ip_dst) {
+        if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
+            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);
+    } else if (flow->tunnel.tun_id) {
+        memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
     }
+
     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);
@@ -81,18 +94,19 @@ match_wc_init(struct match *match, const struct flow *flow)
         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_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)) {
+    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)) {
+    if (is_ip_any(flow)) {
         memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos);
         memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl);
     }
@@ -123,6 +137,7 @@ match_init_exact(struct match *match, const struct flow *flow)
 
     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);
@@ -160,7 +175,7 @@ void
 match_set_reg_masked(struct match *match, unsigned int reg_idx,
                      uint32_t value, uint32_t mask)
 {
-    assert(reg_idx < FLOW_N_REGS);
+    ovs_assert(reg_idx < FLOW_N_REGS);
     flow_wildcards_set_reg_mask(&match->wc, reg_idx, mask);
     match->flow.regs[reg_idx] = value & mask;
 }
@@ -192,6 +207,71 @@ match_set_tun_id_masked(struct match *match, ovs_be64 tun_id, ovs_be64 mask)
     match->flow.tunnel.tun_id = tun_id & mask;
 }
 
+void
+match_set_tun_src(struct match *match, ovs_be32 src)
+{
+    match_set_tun_src_masked(match, src, htonl(UINT32_MAX));
+}
+
+void
+match_set_tun_src_masked(struct match *match, ovs_be32 src, ovs_be32 mask)
+{
+    match->wc.masks.tunnel.ip_src = mask;
+    match->flow.tunnel.ip_src = src & mask;
+}
+
+void
+match_set_tun_dst(struct match *match, ovs_be32 dst)
+{
+    match_set_tun_dst_masked(match, dst, htonl(UINT32_MAX));
+}
+
+void
+match_set_tun_dst_masked(struct match *match, ovs_be32 dst, ovs_be32 mask)
+{
+    match->wc.masks.tunnel.ip_dst = mask;
+    match->flow.tunnel.ip_dst = dst & mask;
+}
+
+void
+match_set_tun_ttl(struct match *match, uint8_t ttl)
+{
+    match_set_tun_ttl_masked(match, ttl, UINT8_MAX);
+}
+
+void
+match_set_tun_ttl_masked(struct match *match, uint8_t ttl, uint8_t mask)
+{
+    match->wc.masks.tunnel.ip_ttl = mask;
+    match->flow.tunnel.ip_ttl = ttl & mask;
+}
+
+void
+match_set_tun_tos(struct match *match, uint8_t tos)
+{
+    match_set_tun_tos_masked(match, tos, UINT8_MAX);
+}
+
+void
+match_set_tun_tos_masked(struct match *match, uint8_t tos, uint8_t mask)
+{
+    match->wc.masks.tunnel.ip_tos = mask;
+    match->flow.tunnel.ip_tos = tos & mask;
+}
+
+void
+match_set_tun_flags(struct match *match, uint16_t flags)
+{
+    match_set_tun_flags_masked(match, flags, UINT16_MAX);
+}
+
+void
+match_set_tun_flags_masked(struct match *match, uint16_t flags, uint16_t mask)
+{
+    match->wc.masks.tunnel.flags = mask;
+    match->flow.tunnel.flags = flags & mask;
+}
+
 void
 match_set_in_port(struct match *match, uint16_t ofp_port)
 {
@@ -199,6 +279,20 @@ match_set_in_port(struct match *match, uint16_t ofp_port)
     match->flow.in_port = ofp_port;
 }
 
+void
+match_set_skb_priority(struct match *match, uint32_t skb_priority)
+{
+    match->wc.masks.skb_priority = UINT32_MAX;
+    match->flow.skb_priority = skb_priority;
+}
+
+void
+match_set_skb_mark(struct match *match, uint32_t skb_mark)
+{
+    match->wc.masks.skb_mark = UINT32_MAX;
+    match->flow.skb_mark = skb_mark;
+}
+
 void
 match_set_dl_type(struct match *match, ovs_be16 dl_type)
 {
@@ -366,6 +460,57 @@ match_set_dl_vlan_pcp(struct match *match, uint8_t dl_vlan_pcp)
     match->wc.masks.vlan_tci |= htons(VLAN_CFI | VLAN_PCP_MASK);
 }
 
+/* Modifies 'match' so that the MPLS label is wildcarded. */
+void
+match_set_any_mpls_label(struct match *match)
+{
+    match->wc.masks.mpls_lse &= ~htonl(MPLS_LABEL_MASK);
+    flow_set_mpls_label(&match->flow, htonl(0));
+}
+
+/* Modifies 'match' so that it matches only packets with an MPLS header whose
+ * label equals the low 20 bits of 'mpls_label'. */
+void
+match_set_mpls_label(struct match *match, ovs_be32 mpls_label)
+{
+    match->wc.masks.mpls_lse |= htonl(MPLS_LABEL_MASK);
+    flow_set_mpls_label(&match->flow, mpls_label);
+}
+
+/* Modifies 'match' so that the MPLS TC is wildcarded. */
+void
+match_set_any_mpls_tc(struct match *match)
+{
+    match->wc.masks.mpls_lse &= ~htonl(MPLS_TC_MASK);
+    flow_set_mpls_tc(&match->flow, 0);
+}
+
+/* Modifies 'match' so that it matches only packets with an MPLS header whose
+ * Traffic Class equals the low 3 bits of 'mpls_tc'. */
+void
+match_set_mpls_tc(struct match *match, uint8_t mpls_tc)
+{
+    match->wc.masks.mpls_lse |= htonl(MPLS_TC_MASK);
+    flow_set_mpls_tc(&match->flow, mpls_tc);
+}
+
+/* Modifies 'match' so that the MPLS stack flag is wildcarded. */
+void
+match_set_any_mpls_bos(struct match *match)
+{
+    match->wc.masks.mpls_lse &= ~htonl(MPLS_BOS_MASK);
+    flow_set_mpls_bos(&match->flow, 0);
+}
+
+/* Modifies 'match' so that it matches only packets with an MPLS header whose
+ * Stack Flag equals the lower bit of 'mpls_bos' */
+void
+match_set_mpls_bos(struct match *match, uint8_t mpls_bos)
+{
+    match->wc.masks.mpls_lse |= htonl(MPLS_BOS_MASK);
+    flow_set_mpls_bos(&match->flow, mpls_bos);
+}
+
 void
 match_set_tp_src(struct match *match, ovs_be16 tp_src)
 {
@@ -640,6 +785,57 @@ format_be16_masked(struct ds *s, const char *name,
     }
 }
 
+static void
+format_flow_tunnel(struct ds *s, const struct match *match)
+{
+    const struct flow_wildcards *wc = &match->wc;
+    const struct flow_tnl *tnl = &match->flow.tunnel;
+
+    switch (wc->masks.tunnel.tun_id) {
+    case 0:
+        break;
+    case CONSTANT_HTONLL(UINT64_MAX):
+        ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(tnl->tun_id));
+        break;
+    default:
+        ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
+                      ntohll(tnl->tun_id),
+                      ntohll(wc->masks.tunnel.tun_id));
+        break;
+    }
+    format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src);
+    format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst);
+
+    if (wc->masks.tunnel.ip_tos) {
+        ds_put_format(s, "tun_tos=%"PRIx8",", tnl->ip_tos);
+    }
+    if (wc->masks.tunnel.ip_ttl) {
+        ds_put_format(s, "tun_ttl=%"PRIu8",", tnl->ip_ttl);
+    }
+    if (wc->masks.tunnel.flags) {
+        format_flags(s, flow_tun_flag_to_string, tnl->flags, '|');
+        ds_put_char(s, ',');
+    }
+}
+
+static void
+flow_format_mpls(const struct flow *flow, struct ds *s)
+{
+    if (flow->dl_type == htons(ETH_TYPE_MPLS)) {
+        ds_put_cstr(s, "mpls");
+    } else if (flow->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+        ds_put_cstr(s, "mplsm");
+    } else {
+        return;
+    }
+
+    ds_put_format(s, "(label:%"PRIu32",tc:%d,ttl:%d,bos:%d),",
+                  mpls_lse_to_label(flow->mpls_lse),
+                  mpls_lse_to_tc(flow->mpls_lse),
+                  mpls_lse_to_ttl(flow->mpls_lse),
+                  mpls_lse_to_bos(flow->mpls_lse));
+}
+
 /* Appends a string representation of 'match' to 's'.  If 'priority' is
  * different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
 void
@@ -653,12 +849,20 @@ 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 == 20);
 
     if (priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%u,", priority);
     }
 
+    if (wc->masks.skb_mark) {
+        ds_put_format(s, "skb_mark=%#"PRIx32",", f->skb_mark);
+    }
+
+    if (wc->masks.skb_priority) {
+        ds_put_format(s, "skb_priority=%#"PRIx32",", f->skb_priority);
+    }
+
     if (wc->masks.dl_type) {
         skip_type = true;
         if (f->dl_type == htons(ETH_TYPE_IP)) {
@@ -695,6 +899,10 @@ 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 if (f->mpls_depth) {
+            flow_format_mpls(f, s);
         } else {
             skip_type = false;
         }
@@ -712,18 +920,9 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
             break;
         }
     }
-    switch (wc->masks.tunnel.tun_id) {
-    case 0:
-        break;
-    case CONSTANT_HTONLL(UINT64_MAX):
-        ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tunnel.tun_id));
-        break;
-    default:
-        ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
-                      ntohll(f->tunnel.tun_id),
-                      ntohll(wc->masks.tunnel.tun_id));
-        break;
-    }
+
+    format_flow_tunnel(s, match);
+
     switch (wc->masks.metadata) {
     case 0:
         break;
@@ -736,7 +935,9 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
         break;
     }
     if (wc->masks.in_port) {
-        ds_put_format(s, "in_port=%"PRIu16",", f->in_port);
+        ds_put_cstr(s, "in_port=");
+        ofputil_format_port(f->in_port, s);
+        ds_put_char(s, ',');
     }
     if (wc->masks.vlan_tci) {
         ovs_be16 vid_mask = wc->masks.vlan_tci & htons(VLAN_VID_MASK);
@@ -780,18 +981,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);
     }
@@ -804,6 +1011,18 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
     if (wc->masks.nw_ttl) {
         ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl);
     }
+    if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
+        ds_put_format(s, "mpls_label=%"PRIu32",",
+                 mpls_lse_to_label(f->mpls_lse));
+    }
+    if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) {
+        ds_put_format(s, "mpls_tc=%"PRIu8",",
+                 mpls_lse_to_tc(f->mpls_lse));
+    }
+    if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
+        ds_put_format(s, "mpls_bos=%"PRIu8",",
+                 mpls_lse_to_bos(f->mpls_lse));
+    }
     switch (wc->masks.nw_frag) {
     case FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER:
         ds_put_format(s, "nw_frag=%s,",