openflow: Support matching and modifying MPLS TTL field.
[cascardo/ovs.git] / lib / match.c
index d527d04..e4b28fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -190,6 +190,36 @@ match_set_tun_dst_masked(struct match *match, ovs_be32 dst, ovs_be32 mask)
     match->flow.tunnel.ip_dst = dst & mask;
 }
 
+void
+match_set_tun_ipv6_src(struct match *match, const struct in6_addr *src)
+{
+    match->flow.tunnel.ipv6_src = *src;
+    match->wc.masks.tunnel.ipv6_src = in6addr_exact;
+}
+
+void
+match_set_tun_ipv6_src_masked(struct match *match, const struct in6_addr *src,
+                              const struct in6_addr *mask)
+{
+    match->flow.tunnel.ipv6_src = ipv6_addr_bitand(src, mask);
+    match->wc.masks.tunnel.ipv6_src = *mask;
+}
+
+void
+match_set_tun_ipv6_dst(struct match *match, const struct in6_addr *dst)
+{
+    match->flow.tunnel.ipv6_dst = *dst;
+    match->wc.masks.tunnel.ipv6_dst = in6addr_exact;
+}
+
+void
+match_set_tun_ipv6_dst_masked(struct match *match, const struct in6_addr *dst,
+                              const struct in6_addr *mask)
+{
+    match->flow.tunnel.ipv6_dst = ipv6_addr_bitand(dst, mask);
+    match->wc.masks.tunnel.ipv6_dst = *mask;
+}
+
 void
 match_set_tun_ttl(struct match *match, uint8_t ttl)
 {
@@ -304,6 +334,38 @@ match_set_ct_zone(struct match *match, uint16_t ct_zone)
     match->wc.masks.ct_zone = UINT16_MAX;
 }
 
+void
+match_set_ct_mark(struct match *match, uint32_t ct_mark)
+{
+    match_set_ct_mark_masked(match, ct_mark, UINT32_MAX);
+}
+
+void
+match_set_ct_mark_masked(struct match *match, uint32_t ct_mark,
+                           uint32_t mask)
+{
+    match->flow.ct_mark = ct_mark & mask;
+    match->wc.masks.ct_mark = mask;
+}
+
+void
+match_set_ct_label(struct match *match, ovs_u128 ct_label)
+{
+    ovs_u128 mask;
+
+    mask.u64.lo = UINT64_MAX;
+    mask.u64.hi = UINT64_MAX;
+    match_set_ct_label_masked(match, ct_label, mask);
+}
+
+void
+match_set_ct_label_masked(struct match *match, ovs_u128 value, ovs_u128 mask)
+{
+    match->flow.ct_label.u64.lo = value.u64.lo & mask.u64.lo;
+    match->flow.ct_label.u64.hi = value.u64.hi & mask.u64.hi;
+    match->wc.masks.ct_label = mask;
+}
+
 void
 match_set_dl_type(struct match *match, ovs_be16 dl_type)
 {
@@ -529,6 +591,23 @@ match_set_mpls_bos(struct match *match, int idx, uint8_t mpls_bos)
     flow_set_mpls_bos(&match->flow, idx, mpls_bos);
 }
 
+/* Modifies 'match' so that the TTL of MPLS label 'idx' is wildcarded. */
+void
+match_set_any_mpls_ttl(struct match *match, int idx)
+{
+    match->wc.masks.mpls_lse[idx] &= ~htonl(MPLS_TTL_MASK);
+    flow_set_mpls_ttl(&match->flow, idx, 0);
+}
+
+/* Modifies 'match' so that it matches only packets in which the TTL of MPLS
+ * label 'idx' equals 'mpls_ttl'. */
+void
+match_set_mpls_ttl(struct match *match, int idx, uint8_t mpls_ttl)
+{
+    match->wc.masks.mpls_lse[idx] |= htonl(MPLS_TTL_MASK);
+    flow_set_mpls_ttl(&match->flow, idx, mpls_ttl);
+}
+
 /* Modifies 'match' so that the MPLS LSE is wildcarded. */
 void
 match_set_any_mpls_lse(struct match *match, int idx)
@@ -830,7 +909,7 @@ format_ipv6_netmask(struct ds *s, const char *name,
 {
     if (!ipv6_mask_is_any(netmask)) {
         ds_put_format(s, "%s=", name);
-        print_ipv6_masked(s, addr, netmask);
+        ipv6_format_masked(addr, netmask, s);
         ds_put_char(s, ',');
     }
 }
@@ -917,6 +996,10 @@ format_flow_tunnel(struct ds *s, const struct match *match)
     format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id);
     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);
+    format_ipv6_netmask(s, "tun_ipv6_src", &tnl->ipv6_src,
+                        &wc->masks.tunnel.ipv6_src);
+    format_ipv6_netmask(s, "tun_ipv6_dst", &tnl->ipv6_dst,
+                        &wc->masks.tunnel.ipv6_dst);
 
     if (wc->masks.tunnel.gbp_id) {
         format_be16_masked(s, "tun_gbp_id", tnl->gbp_id,
@@ -943,6 +1026,22 @@ format_flow_tunnel(struct ds *s, const struct match *match)
     tun_metadata_match_format(s, match);
 }
 
+static void
+format_ct_label_masked(struct ds *s, const ovs_u128 *key, const ovs_u128 *mask)
+{
+    if (!ovs_u128_is_zero(mask)) {
+        ovs_be128 value = hton128(*key);
+        ds_put_format(s, "ct_label=");
+        ds_put_hex(s, &value, sizeof value);
+        if (!is_all_ones(mask, sizeof(*mask))) {
+            value = hton128(*mask);
+            ds_put_char(s, '/');
+            ds_put_hex(s, &value, sizeof value);
+        }
+        ds_put_char(s, ',');
+    }
+}
+
 /* Appends a string representation of 'match' to 's'.  If 'priority' is
  * different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
 void
@@ -956,7 +1055,7 @@ match_format(const struct match *match, struct ds *s, int priority)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 34);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
 
     if (priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%d,", priority);
@@ -1007,6 +1106,14 @@ match_format(const struct match *match, struct ds *s, int priority)
         format_uint16_masked(s, "ct_zone", f->ct_zone, wc->masks.ct_zone);
     }
 
+    if (wc->masks.ct_mark) {
+        format_uint32_masked(s, "ct_mark", f->ct_mark, wc->masks.ct_mark);
+    }
+
+    if (!ovs_u128_is_zero(&wc->masks.ct_label)) {
+        format_ct_label_masked(s, &f->ct_label, &wc->masks.ct_label);
+    }
+
     if (wc->masks.dl_type) {
         skip_type = true;
         if (f->dl_type == htons(ETH_TYPE_IP)) {