/*
- * 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"
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);
+ if (flow->pkt_mark) {
+ memset(&wc->masks.pkt_mark, 0xff, sizeof wc->masks.pkt_mark);
}
for (i = 0; i < FLOW_N_REGS; i++) {
(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);
+ } else if (eth_type_mpls(flow->dl_type)) {
+ memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
}
if (flow->dl_type == htons(ETH_TYPE_ARP) ||
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);
- }
- if (flow->nw_frag) {
- memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag);
- }
+ 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_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);
+ 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;
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);
}
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;
}
}
void
-match_set_in_port(struct match *match, uint16_t ofp_port)
+match_set_in_port(struct match *match, ofp_port_t ofp_port)
{
- match->wc.masks.in_port = UINT16_MAX;
- match->flow.in_port = ofp_port;
+ match->wc.masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX);
+ match->flow.in_port.ofp_port = ofp_port;
}
void
}
void
-match_set_skb_mark(struct match *match, uint32_t skb_mark)
+match_set_pkt_mark(struct match *match, uint32_t pkt_mark)
+{
+ match_set_pkt_mark_masked(match, pkt_mark, UINT32_MAX);
+}
+
+void
+match_set_pkt_mark_masked(struct match *match, uint32_t pkt_mark, uint32_t mask)
{
- match->wc.masks.skb_mark = UINT32_MAX;
- match->flow.skb_mark = skb_mark;
+ match->flow.pkt_mark = pkt_mark & mask;
+ match->wc.masks.pkt_mark = mask;
}
void
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)
{
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+ 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);
+ switch (wc->masks.pkt_mark) {
+ case 0:
+ break;
+ case UINT32_MAX:
+ ds_put_format(s, "pkt_mark=%#"PRIx32",", f->pkt_mark);
+ break;
+ default:
+ ds_put_format(s, "pkt_mark=%#"PRIx32"/%#"PRIx32",",
+ f->pkt_mark, wc->masks.pkt_mark);
+ break;
}
if (wc->masks.skb_priority) {
ds_put_cstr(s, "tcp,");
} else if (f->nw_proto == IPPROTO_UDP) {
ds_put_cstr(s, "udp,");
+ } else if (f->nw_proto == IPPROTO_SCTP) {
+ ds_put_cstr(s, "sctp,");
} else {
ds_put_cstr(s, "ip,");
skip_proto = false;
ds_put_cstr(s, "tcp6,");
} else if (f->nw_proto == IPPROTO_UDP) {
ds_put_cstr(s, "udp6,");
+ } else if (f->nw_proto == IPPROTO_SCTP) {
+ ds_put_cstr(s, "sctp6,");
} else {
ds_put_cstr(s, "ipv6,");
skip_proto = false;
ds_put_cstr(s, "arp,");
} else if (f->dl_type == htons(ETH_TYPE_RARP)) {
ds_put_cstr(s, "rarp,");
+ } else if (f->dl_type == htons(ETH_TYPE_MPLS)) {
+ ds_put_cstr(s, "mpls,");
+ } else if (f->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+ ds_put_cstr(s, "mplsm,");
} else {
skip_type = false;
}
ntohll(f->metadata), ntohll(wc->masks.metadata));
break;
}
- if (wc->masks.in_port) {
+ if (wc->masks.in_port.ofp_port) {
ds_put_cstr(s, "in_port=");
- ofputil_format_port(f->in_port, s);
+ ofputil_format_port(f->in_port.ofp_port, s);
ds_put_char(s, ',');
}
if (wc->masks.vlan_tci) {
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_TTL_MASK)) {
+ ds_put_format(s, "mpls_ttl=%"PRIu8",",
+ mpls_lse_to_ttl(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,",
minimask_clone(&dst->mask, &src->mask);
}
+/* Initializes 'dst' with the data in 'src', destroying 'src'. The caller must
+ * eventually free 'dst' with minimatch_destroy(). */
+void
+minimatch_move(struct minimatch *dst, struct minimatch *src)
+{
+ miniflow_move(&dst->flow, &src->flow);
+ minimask_move(&dst->mask, &src->mask);
+}
+
/* Frees any memory owned by 'match'. Does not free the storage in which
* 'match' itself resides; the caller is responsible for that. */
void