mirror of
https://github.com/openvswitch/ovs
synced 2025-09-02 15:25:22 +00:00
flow: Adds support for arbitrary ethernet masking
Arbitrary ethernet mask support is one step on the way to support for OpenFlow 1.1+. This patch set seeks to add this capability without breaking current protocol support. Signed-off-by: Joe Stringer <joe@wand.net.nz> [blp@nicira.com made some updates, see http://openvswitch.org/pipermail/dev/2012-May/017585.html] Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
1
NEWS
1
NEWS
@@ -2,6 +2,7 @@ post-v1.7.0
|
||||
------------------------
|
||||
- ovs-ofctl:
|
||||
- "mod-port" command can now control all OpenFlow config flags.
|
||||
- Added support for arbitrary ethernet masks
|
||||
|
||||
|
||||
v1.7.0 - xx xxx xxxx
|
||||
|
@@ -1368,13 +1368,13 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
|
||||
*
|
||||
* Format: 48-bit Ethernet MAC address.
|
||||
*
|
||||
* Masking: The nxm_mask patterns 01:00:00:00:00:00 and FE:FF:FF:FF:FF:FF must
|
||||
* be supported for NXM_OF_ETH_DST_W (as well as the trivial patterns that
|
||||
* are all-0-bits or all-1-bits). Support for other patterns and for masking
|
||||
* of NXM_OF_ETH_SRC is optional. */
|
||||
* Masking: Fully maskable, in versions 1.8 and later. Earlier versions only
|
||||
* supported the following masks for NXM_OF_ETH_DST_W: 00:00:00:00:00:00,
|
||||
* fe:ff:ff:ff:ff:ff, 01:00:00:00:00:00, ff:ff:ff:ff:ff:ff. */
|
||||
#define NXM_OF_ETH_DST NXM_HEADER (0x0000, 1, 6)
|
||||
#define NXM_OF_ETH_DST_W NXM_HEADER_W(0x0000, 1, 6)
|
||||
#define NXM_OF_ETH_SRC NXM_HEADER (0x0000, 2, 6)
|
||||
#define NXM_OF_ETH_SRC_W NXM_HEADER_W(0x0000, 2, 6)
|
||||
|
||||
/* Packet's Ethernet type.
|
||||
*
|
||||
|
@@ -149,16 +149,31 @@ cls_rule_set_dl_type(struct cls_rule *rule, ovs_be16 dl_type)
|
||||
void
|
||||
cls_rule_set_dl_src(struct cls_rule *rule, const uint8_t dl_src[ETH_ADDR_LEN])
|
||||
{
|
||||
rule->wc.wildcards &= ~FWW_DL_SRC;
|
||||
memcpy(rule->flow.dl_src, dl_src, ETH_ADDR_LEN);
|
||||
memset(rule->wc.dl_src_mask, 0xff, ETH_ADDR_LEN);
|
||||
}
|
||||
|
||||
/* Modifies 'rule' so that the Ethernet address must match 'dl_src' after each
|
||||
* byte is ANDed with the appropriate byte in 'mask'. */
|
||||
void
|
||||
cls_rule_set_dl_src_masked(struct cls_rule *rule,
|
||||
const uint8_t dl_src[ETH_ADDR_LEN],
|
||||
const uint8_t mask[ETH_ADDR_LEN])
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ETH_ADDR_LEN; i++) {
|
||||
rule->flow.dl_src[i] = dl_src[i] & mask[i];
|
||||
rule->wc.dl_src_mask[i] = mask[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Modifies 'rule' so that the Ethernet address must match 'dl_dst' exactly. */
|
||||
void
|
||||
cls_rule_set_dl_dst(struct cls_rule *rule, const uint8_t dl_dst[ETH_ADDR_LEN])
|
||||
{
|
||||
rule->wc.wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
|
||||
memcpy(rule->flow.dl_dst, dl_dst, ETH_ADDR_LEN);
|
||||
memset(rule->wc.dl_dst_mask, 0xff, ETH_ADDR_LEN);
|
||||
}
|
||||
|
||||
/* Modifies 'rule' so that the Ethernet address must match 'dl_dst' after each
|
||||
@@ -171,12 +186,11 @@ cls_rule_set_dl_dst_masked(struct cls_rule *rule,
|
||||
const uint8_t dl_dst[ETH_ADDR_LEN],
|
||||
const uint8_t mask[ETH_ADDR_LEN])
|
||||
{
|
||||
flow_wildcards_t *wc = &rule->wc.wildcards;
|
||||
size_t i;
|
||||
|
||||
*wc = flow_wildcards_set_dl_dst_mask(*wc, mask);
|
||||
for (i = 0; i < ETH_ADDR_LEN; i++) {
|
||||
rule->flow.dl_dst[i] = dl_dst[i] & mask[i];
|
||||
rule->wc.dl_dst_mask[i] = mask[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,6 +462,17 @@ cls_rule_hash(const struct cls_rule *rule, uint32_t basis)
|
||||
return hash_int(rule->priority, h1);
|
||||
}
|
||||
|
||||
static void
|
||||
format_eth_masked(struct ds *s, const char *name, const uint8_t eth[6],
|
||||
const uint8_t mask[6])
|
||||
{
|
||||
if (!eth_addr_is_zero(mask)) {
|
||||
ds_put_format(s, "%s=", name);
|
||||
eth_format_masked(eth, mask, s);
|
||||
ds_put_char(s, ',');
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
format_ip_netmask(struct ds *s, const char *name, ovs_be32 ip,
|
||||
ovs_be32 netmask)
|
||||
@@ -500,7 +525,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
|
||||
|
||||
int i;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
if (rule->priority != OFP_DEFAULT_PRIORITY) {
|
||||
ds_put_format(s, "priority=%d,", rule->priority);
|
||||
@@ -597,24 +622,8 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
|
||||
ntohs(f->vlan_tci), ntohs(wc->vlan_tci_mask));
|
||||
}
|
||||
}
|
||||
if (!(w & FWW_DL_SRC)) {
|
||||
ds_put_format(s, "dl_src="ETH_ADDR_FMT",", ETH_ADDR_ARGS(f->dl_src));
|
||||
}
|
||||
switch (w & (FWW_DL_DST | FWW_ETH_MCAST)) {
|
||||
case 0:
|
||||
ds_put_format(s, "dl_dst="ETH_ADDR_FMT",", ETH_ADDR_ARGS(f->dl_dst));
|
||||
break;
|
||||
case FWW_DL_DST:
|
||||
ds_put_format(s, "dl_dst="ETH_ADDR_FMT"/01:00:00:00:00:00,",
|
||||
ETH_ADDR_ARGS(f->dl_dst));
|
||||
break;
|
||||
case FWW_ETH_MCAST:
|
||||
ds_put_format(s, "dl_dst="ETH_ADDR_FMT"/fe:ff:ff:ff:ff:ff,",
|
||||
ETH_ADDR_ARGS(f->dl_dst));
|
||||
break;
|
||||
case FWW_DL_DST | FWW_ETH_MCAST:
|
||||
break;
|
||||
}
|
||||
format_eth_masked(s, "dl_src", f->dl_src, wc->dl_src_mask);
|
||||
format_eth_masked(s, "dl_dst", f->dl_dst, wc->dl_dst_mask);
|
||||
if (!skip_type && !(w & FWW_DL_TYPE)) {
|
||||
ds_put_format(s, "dl_type=0x%04"PRIx16",", ntohs(f->dl_type));
|
||||
}
|
||||
@@ -1179,7 +1188,7 @@ flow_equal_except(const struct flow *a, const struct flow *b,
|
||||
const flow_wildcards_t wc = wildcards->wildcards;
|
||||
int i;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
for (i = 0; i < FLOW_N_REGS; i++) {
|
||||
if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) {
|
||||
@@ -1195,16 +1204,10 @@ flow_equal_except(const struct flow *a, const struct flow *b,
|
||||
&& (wc & FWW_DL_TYPE || a->dl_type == b->dl_type)
|
||||
&& !((a->tp_src ^ b->tp_src) & wildcards->tp_src_mask)
|
||||
&& !((a->tp_dst ^ b->tp_dst) & wildcards->tp_dst_mask)
|
||||
&& (wc & FWW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src))
|
||||
&& (wc & FWW_DL_DST
|
||||
|| (!((a->dl_dst[0] ^ b->dl_dst[0]) & 0xfe)
|
||||
&& a->dl_dst[1] == b->dl_dst[1]
|
||||
&& a->dl_dst[2] == b->dl_dst[2]
|
||||
&& a->dl_dst[3] == b->dl_dst[3]
|
||||
&& a->dl_dst[4] == b->dl_dst[4]
|
||||
&& a->dl_dst[5] == b->dl_dst[5]))
|
||||
&& (wc & FWW_ETH_MCAST
|
||||
|| !((a->dl_dst[0] ^ b->dl_dst[0]) & 0x01))
|
||||
&& !eth_addr_equal_except(a->dl_src, b->dl_src,
|
||||
wildcards->dl_src_mask)
|
||||
&& !eth_addr_equal_except(a->dl_dst, b->dl_dst,
|
||||
wildcards->dl_dst_mask)
|
||||
&& (wc & FWW_NW_PROTO || a->nw_proto == b->nw_proto)
|
||||
&& (wc & FWW_NW_TTL || a->nw_ttl == b->nw_ttl)
|
||||
&& (wc & FWW_NW_DSCP || !((a->nw_tos ^ b->nw_tos) & IP_DSCP_MASK))
|
||||
|
@@ -96,6 +96,8 @@ void cls_rule_set_tun_id_masked(struct cls_rule *,
|
||||
void cls_rule_set_in_port(struct cls_rule *, uint16_t ofp_port);
|
||||
void cls_rule_set_dl_type(struct cls_rule *, ovs_be16);
|
||||
void cls_rule_set_dl_src(struct cls_rule *, const uint8_t[6]);
|
||||
void cls_rule_set_dl_src_masked(struct cls_rule *, const uint8_t dl_src[6],
|
||||
const uint8_t mask[6]);
|
||||
void cls_rule_set_dl_dst(struct cls_rule *, const uint8_t[6]);
|
||||
void cls_rule_set_dl_dst_masked(struct cls_rule *, const uint8_t dl_dst[6],
|
||||
const uint8_t mask[6]);
|
||||
|
134
lib/flow.c
134
lib/flow.c
@@ -444,7 +444,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
|
||||
const flow_wildcards_t wc = wildcards->wildcards;
|
||||
int i;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
for (i = 0; i < FLOW_N_REGS; i++) {
|
||||
flow->regs[i] &= wildcards->reg_masks[i];
|
||||
@@ -461,16 +461,8 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
|
||||
}
|
||||
flow->tp_src &= wildcards->tp_src_mask;
|
||||
flow->tp_dst &= wildcards->tp_dst_mask;
|
||||
if (wc & FWW_DL_SRC) {
|
||||
memset(flow->dl_src, 0, sizeof flow->dl_src);
|
||||
}
|
||||
if (wc & FWW_DL_DST) {
|
||||
flow->dl_dst[0] &= 0x01;
|
||||
memset(&flow->dl_dst[1], 0, 5);
|
||||
}
|
||||
if (wc & FWW_ETH_MCAST) {
|
||||
flow->dl_dst[0] &= 0xfe;
|
||||
}
|
||||
eth_addr_bitand(flow->dl_src, wildcards->dl_src_mask, flow->dl_src);
|
||||
eth_addr_bitand(flow->dl_dst, wildcards->dl_dst_mask, flow->dl_dst);
|
||||
if (wc & FWW_NW_PROTO) {
|
||||
flow->nw_proto = 0;
|
||||
}
|
||||
@@ -506,7 +498,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
|
||||
void
|
||||
flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
|
||||
{
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
fmd->tun_id = flow->tun_id;
|
||||
fmd->tun_id_mask = htonll(UINT64_MAX);
|
||||
@@ -595,7 +587,7 @@ flow_print(FILE *stream, const struct flow *flow)
|
||||
void
|
||||
flow_wildcards_init_catchall(struct flow_wildcards *wc)
|
||||
{
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
wc->wildcards = FWW_ALL;
|
||||
wc->tun_id_mask = htonll(0);
|
||||
@@ -609,6 +601,8 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc)
|
||||
wc->nw_frag_mask = 0;
|
||||
wc->tp_src_mask = htons(0);
|
||||
wc->tp_dst_mask = htons(0);
|
||||
memset(wc->dl_src_mask, 0, ETH_ADDR_LEN);
|
||||
memset(wc->dl_dst_mask, 0, ETH_ADDR_LEN);
|
||||
memset(wc->zeros, 0, sizeof wc->zeros);
|
||||
}
|
||||
|
||||
@@ -617,7 +611,7 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc)
|
||||
void
|
||||
flow_wildcards_init_exact(struct flow_wildcards *wc)
|
||||
{
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
wc->wildcards = 0;
|
||||
wc->tun_id_mask = htonll(UINT64_MAX);
|
||||
@@ -631,6 +625,8 @@ flow_wildcards_init_exact(struct flow_wildcards *wc)
|
||||
wc->nw_frag_mask = UINT8_MAX;
|
||||
wc->tp_src_mask = htons(UINT16_MAX);
|
||||
wc->tp_dst_mask = htons(UINT16_MAX);
|
||||
memset(wc->dl_src_mask, 0xff, ETH_ADDR_LEN);
|
||||
memset(wc->dl_dst_mask, 0xff, ETH_ADDR_LEN);
|
||||
memset(wc->zeros, 0, sizeof wc->zeros);
|
||||
}
|
||||
|
||||
@@ -641,7 +637,7 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc)
|
||||
{
|
||||
int i;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
if (wc->wildcards
|
||||
|| wc->tun_id_mask != htonll(UINT64_MAX)
|
||||
@@ -650,6 +646,8 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc)
|
||||
|| wc->tp_src_mask != htons(UINT16_MAX)
|
||||
|| wc->tp_dst_mask != htons(UINT16_MAX)
|
||||
|| wc->vlan_tci_mask != htons(UINT16_MAX)
|
||||
|| !eth_mask_is_exact(wc->dl_src_mask)
|
||||
|| !eth_mask_is_exact(wc->dl_dst_mask)
|
||||
|| !ipv6_mask_is_exact(&wc->ipv6_src_mask)
|
||||
|| !ipv6_mask_is_exact(&wc->ipv6_dst_mask)
|
||||
|| !ipv6_mask_is_exact(&wc->nd_target_mask)
|
||||
@@ -673,7 +671,7 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc)
|
||||
{
|
||||
int i;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
if (wc->wildcards != FWW_ALL
|
||||
|| wc->tun_id_mask != htonll(0)
|
||||
@@ -682,6 +680,8 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc)
|
||||
|| wc->tp_src_mask != htons(0)
|
||||
|| wc->tp_dst_mask != htons(0)
|
||||
|| wc->vlan_tci_mask != htons(0)
|
||||
|| !eth_addr_is_zero(wc->dl_src_mask)
|
||||
|| !eth_addr_is_zero(wc->dl_dst_mask)
|
||||
|| !ipv6_mask_is_any(&wc->ipv6_src_mask)
|
||||
|| !ipv6_mask_is_any(&wc->ipv6_dst_mask)
|
||||
|| !ipv6_mask_is_any(&wc->nd_target_mask)
|
||||
@@ -708,7 +708,7 @@ flow_wildcards_combine(struct flow_wildcards *dst,
|
||||
{
|
||||
int i;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
dst->wildcards = src1->wildcards | src2->wildcards;
|
||||
dst->tun_id_mask = src1->tun_id_mask & src2->tun_id_mask;
|
||||
@@ -726,6 +726,8 @@ flow_wildcards_combine(struct flow_wildcards *dst,
|
||||
dst->vlan_tci_mask = src1->vlan_tci_mask & src2->vlan_tci_mask;
|
||||
dst->tp_src_mask = src1->tp_src_mask & src2->tp_src_mask;
|
||||
dst->tp_dst_mask = src1->tp_dst_mask & src2->tp_dst_mask;
|
||||
eth_addr_bitand(src1->dl_src_mask, src2->dl_src_mask, dst->dl_src_mask);
|
||||
eth_addr_bitand(src1->dl_dst_mask, src2->dl_dst_mask, dst->dl_dst_mask);
|
||||
}
|
||||
|
||||
/* Returns a hash of the wildcards in 'wc'. */
|
||||
@@ -735,7 +737,7 @@ flow_wildcards_hash(const struct flow_wildcards *wc, uint32_t basis)
|
||||
/* If you change struct flow_wildcards and thereby trigger this
|
||||
* assertion, please check that the new struct flow_wildcards has no holes
|
||||
* in it before you update the assertion. */
|
||||
BUILD_ASSERT_DECL(sizeof *wc == 80 + FLOW_N_REGS * 4);
|
||||
BUILD_ASSERT_DECL(sizeof *wc == 88 + FLOW_N_REGS * 4);
|
||||
return hash_bytes(wc, sizeof *wc, basis);
|
||||
}
|
||||
|
||||
@@ -747,7 +749,7 @@ flow_wildcards_equal(const struct flow_wildcards *a,
|
||||
{
|
||||
int i;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
if (a->wildcards != b->wildcards
|
||||
|| a->tun_id_mask != b->tun_id_mask
|
||||
@@ -758,7 +760,9 @@ flow_wildcards_equal(const struct flow_wildcards *a,
|
||||
|| !ipv6_addr_equals(&a->ipv6_dst_mask, &b->ipv6_dst_mask)
|
||||
|| !ipv6_addr_equals(&a->nd_target_mask, &b->nd_target_mask)
|
||||
|| a->tp_src_mask != b->tp_src_mask
|
||||
|| a->tp_dst_mask != b->tp_dst_mask) {
|
||||
|| a->tp_dst_mask != b->tp_dst_mask
|
||||
|| !eth_addr_equals(a->dl_src_mask, b->dl_src_mask)
|
||||
|| !eth_addr_equals(a->dl_dst_mask, b->dl_dst_mask)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -778,9 +782,10 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
|
||||
const struct flow_wildcards *b)
|
||||
{
|
||||
int i;
|
||||
uint8_t eth_masked[ETH_ADDR_LEN];
|
||||
struct in6_addr ipv6_masked;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
for (i = 0; i < FLOW_N_REGS; i++) {
|
||||
if ((a->reg_masks[i] & b->reg_masks[i]) != b->reg_masks[i]) {
|
||||
@@ -788,6 +793,16 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
|
||||
}
|
||||
}
|
||||
|
||||
eth_addr_bitand(a->dl_src_mask, b->dl_src_mask, eth_masked);
|
||||
if (!eth_addr_equals(eth_masked, b->dl_src_mask)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
eth_addr_bitand(a->dl_dst_mask, b->dl_dst_mask, eth_masked);
|
||||
if (!eth_addr_equals(eth_masked, b->dl_dst_mask)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ipv6_masked = ipv6_addr_bitand(&a->ipv6_src_mask, &b->ipv6_src_mask);
|
||||
if (!ipv6_addr_equals(&ipv6_masked, &b->ipv6_src_mask)) {
|
||||
return true;
|
||||
@@ -820,83 +835,6 @@ flow_wildcards_set_reg_mask(struct flow_wildcards *wc, int idx, uint32_t mask)
|
||||
wc->reg_masks[idx] = mask;
|
||||
}
|
||||
|
||||
/* Returns the wildcard bitmask for the Ethernet destination address
|
||||
* that 'wc' specifies. The bitmask has a 0 in each bit that is wildcarded
|
||||
* and a 1 in each bit that must match. */
|
||||
const uint8_t *
|
||||
flow_wildcards_to_dl_dst_mask(flow_wildcards_t wc)
|
||||
{
|
||||
static const uint8_t no_wild[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
static const uint8_t addr_wild[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
static const uint8_t mcast_wild[] = {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
static const uint8_t all_wild[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
switch (wc & (FWW_DL_DST | FWW_ETH_MCAST)) {
|
||||
case 0: return no_wild;
|
||||
case FWW_DL_DST: return addr_wild;
|
||||
case FWW_ETH_MCAST: return mcast_wild;
|
||||
case FWW_DL_DST | FWW_ETH_MCAST: return all_wild;
|
||||
}
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
/* Returns true if 'mask' is a valid wildcard bitmask for the Ethernet
|
||||
* destination address. Valid bitmasks are either all-bits-0 or all-bits-1,
|
||||
* except that the multicast bit may differ from the rest of the bits. So,
|
||||
* there are four possible valid bitmasks:
|
||||
*
|
||||
* - 00:00:00:00:00:00
|
||||
* - 01:00:00:00:00:00
|
||||
* - fe:ff:ff:ff:ff:ff
|
||||
* - ff:ff:ff:ff:ff:ff
|
||||
*
|
||||
* All other bitmasks are invalid. */
|
||||
bool
|
||||
flow_wildcards_is_dl_dst_mask_valid(const uint8_t mask[ETH_ADDR_LEN])
|
||||
{
|
||||
switch (mask[0]) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
return (mask[1] | mask[2] | mask[3] | mask[4] | mask[5]) == 0x00;
|
||||
|
||||
case 0xfe:
|
||||
case 0xff:
|
||||
return (mask[1] & mask[2] & mask[3] & mask[4] & mask[5]) == 0xff;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns 'wc' with the FWW_DL_DST and FWW_ETH_MCAST bits modified
|
||||
* appropriately to match 'mask'.
|
||||
*
|
||||
* This function will assert-fail if 'mask' is invalid. Only 'mask' values
|
||||
* accepted by flow_wildcards_is_dl_dst_mask_valid() are allowed. */
|
||||
flow_wildcards_t
|
||||
flow_wildcards_set_dl_dst_mask(flow_wildcards_t wc,
|
||||
const uint8_t mask[ETH_ADDR_LEN])
|
||||
{
|
||||
assert(flow_wildcards_is_dl_dst_mask_valid(mask));
|
||||
|
||||
switch (mask[0]) {
|
||||
case 0x00:
|
||||
return wc | FWW_DL_DST | FWW_ETH_MCAST;
|
||||
|
||||
case 0x01:
|
||||
return (wc | FWW_DL_DST) & ~FWW_ETH_MCAST;
|
||||
|
||||
case 0xfe:
|
||||
return (wc & ~FWW_DL_DST) | FWW_ETH_MCAST;
|
||||
|
||||
case 0xff:
|
||||
return wc & ~(FWW_DL_DST | FWW_ETH_MCAST);
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/* Hashes 'flow' based on its L2 through L4 protocol information. */
|
||||
uint32_t
|
||||
flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis)
|
||||
|
31
lib/flow.h
31
lib/flow.h
@@ -35,7 +35,7 @@ struct ofpbuf;
|
||||
/* This sequence number should be incremented whenever anything involving flows
|
||||
* or the wildcarding of flows changes. This will cause build assertion
|
||||
* failures in places which likely need to be updated. */
|
||||
#define FLOW_WC_SEQ 10
|
||||
#define FLOW_WC_SEQ 11
|
||||
|
||||
#define FLOW_N_REGS 8
|
||||
BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
|
||||
@@ -100,7 +100,7 @@ BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nw_frag) == 1);
|
||||
BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE);
|
||||
|
||||
/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
|
||||
BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 142 && FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 142 && FLOW_WC_SEQ == 11);
|
||||
|
||||
void flow_extract(struct ofpbuf *, uint32_t priority, ovs_be64 tun_id,
|
||||
uint16_t in_port, struct flow *);
|
||||
@@ -147,24 +147,19 @@ typedef unsigned int OVS_BITWISE flow_wildcards_t;
|
||||
|
||||
/* Same values and meanings as corresponding OFPFW_* bits. */
|
||||
#define FWW_IN_PORT ((OVS_FORCE flow_wildcards_t) (1 << 0))
|
||||
#define FWW_DL_SRC ((OVS_FORCE flow_wildcards_t) (1 << 2))
|
||||
#define FWW_DL_DST ((OVS_FORCE flow_wildcards_t) (1 << 3))
|
||||
/* excluding the multicast bit */
|
||||
#define FWW_DL_TYPE ((OVS_FORCE flow_wildcards_t) (1 << 4))
|
||||
#define FWW_NW_PROTO ((OVS_FORCE flow_wildcards_t) (1 << 5))
|
||||
/* No corresponding OFPFW_* bits. */
|
||||
#define FWW_ETH_MCAST ((OVS_FORCE flow_wildcards_t) (1 << 1))
|
||||
/* multicast bit only */
|
||||
#define FWW_NW_DSCP ((OVS_FORCE flow_wildcards_t) (1 << 6))
|
||||
#define FWW_NW_ECN ((OVS_FORCE flow_wildcards_t) (1 << 7))
|
||||
#define FWW_ARP_SHA ((OVS_FORCE flow_wildcards_t) (1 << 8))
|
||||
#define FWW_ARP_THA ((OVS_FORCE flow_wildcards_t) (1 << 9))
|
||||
#define FWW_IPV6_LABEL ((OVS_FORCE flow_wildcards_t) (1 << 10))
|
||||
#define FWW_NW_TTL ((OVS_FORCE flow_wildcards_t) (1 << 11))
|
||||
#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 12)) - 1))
|
||||
#define FWW_NW_DSCP ((OVS_FORCE flow_wildcards_t) (1 << 1))
|
||||
#define FWW_NW_ECN ((OVS_FORCE flow_wildcards_t) (1 << 2))
|
||||
#define FWW_ARP_SHA ((OVS_FORCE flow_wildcards_t) (1 << 3))
|
||||
#define FWW_ARP_THA ((OVS_FORCE flow_wildcards_t) (1 << 6))
|
||||
#define FWW_IPV6_LABEL ((OVS_FORCE flow_wildcards_t) (1 << 7))
|
||||
#define FWW_NW_TTL ((OVS_FORCE flow_wildcards_t) (1 << 8))
|
||||
#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 9)) - 1))
|
||||
|
||||
/* Remember to update FLOW_WC_SEQ when adding or removing FWW_*. */
|
||||
BUILD_ASSERT_DECL(FWW_ALL == ((1 << 12) - 1) && FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FWW_ALL == ((1 << 9) - 1) && FLOW_WC_SEQ == 11);
|
||||
|
||||
/* Information on wildcards for a flow, as a supplement to "struct flow".
|
||||
*
|
||||
@@ -184,11 +179,13 @@ struct flow_wildcards {
|
||||
ovs_be16 tp_src_mask; /* 1-bit in each significant tp_src bit. */
|
||||
ovs_be16 tp_dst_mask; /* 1-bit in each significant tp_dst bit. */
|
||||
uint8_t nw_frag_mask; /* 1-bit in each significant nw_frag bit. */
|
||||
uint8_t zeros[5]; /* Padding field set to zero. */
|
||||
uint8_t dl_src_mask[6]; /* 1-bit in each significant dl_src bit. */
|
||||
uint8_t dl_dst_mask[6]; /* 1-bit in each significant dl_dst bit. */
|
||||
uint8_t zeros[1]; /* Padding field set to zero. */
|
||||
};
|
||||
|
||||
/* Remember to update FLOW_WC_SEQ when updating struct flow_wildcards. */
|
||||
BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 112 && FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 120 && FLOW_WC_SEQ == 11);
|
||||
|
||||
void flow_wildcards_init_catchall(struct flow_wildcards *);
|
||||
void flow_wildcards_init_exact(struct flow_wildcards *);
|
||||
|
@@ -184,7 +184,7 @@ learn_check(const struct nx_action_learn *learn, const struct flow *flow)
|
||||
* prerequisites. No prerequisite depends on the value of
|
||||
* a field that is wider than 64 bits. So just skip
|
||||
* setting it entirely. */
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -113,7 +113,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
|
||||
{
|
||||
MFF_ETH_SRC, "eth_src", "dl_src",
|
||||
MF_FIELD_SIZES(mac),
|
||||
MFM_NONE, FWW_DL_SRC,
|
||||
MFM_FULLY, 0,
|
||||
MFS_ETHERNET,
|
||||
MFP_NONE,
|
||||
true,
|
||||
@@ -122,7 +122,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
|
||||
}, {
|
||||
MFF_ETH_DST, "eth_dst", "dl_dst",
|
||||
MF_FIELD_SIZES(mac),
|
||||
MFM_MCAST, 0,
|
||||
MFM_FULLY, 0,
|
||||
MFS_ETHERNET,
|
||||
MFP_NONE,
|
||||
true,
|
||||
@@ -543,7 +543,6 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
|
||||
{
|
||||
switch (mf->id) {
|
||||
case MFF_IN_PORT:
|
||||
case MFF_ETH_SRC:
|
||||
case MFF_ETH_TYPE:
|
||||
case MFF_IP_PROTO:
|
||||
case MFF_IP_DSCP:
|
||||
@@ -590,9 +589,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
|
||||
#endif
|
||||
return !wc->reg_masks[mf->id - MFF_REG0];
|
||||
|
||||
case MFF_ETH_SRC:
|
||||
return eth_addr_is_zero(wc->dl_src_mask);
|
||||
case MFF_ETH_DST:
|
||||
return ((wc->wildcards & (FWW_ETH_MCAST | FWW_DL_DST))
|
||||
== (FWW_ETH_MCAST | FWW_DL_DST));
|
||||
return eth_addr_is_zero(wc->dl_dst_mask);
|
||||
|
||||
case MFF_VLAN_TCI:
|
||||
return !wc->vlan_tci_mask;
|
||||
@@ -651,7 +651,6 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
|
||||
{
|
||||
switch (mf->id) {
|
||||
case MFF_IN_PORT:
|
||||
case MFF_ETH_SRC:
|
||||
case MFF_ETH_TYPE:
|
||||
case MFF_IP_PROTO:
|
||||
case MFF_IP_DSCP:
|
||||
@@ -702,8 +701,11 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
|
||||
break;
|
||||
|
||||
case MFF_ETH_DST:
|
||||
memcpy(mask->mac, flow_wildcards_to_dl_dst_mask(wc->wildcards),
|
||||
ETH_ADDR_LEN);
|
||||
memcpy(mask->mac, wc->dl_dst_mask, ETH_ADDR_LEN);
|
||||
break;
|
||||
|
||||
case MFF_ETH_SRC:
|
||||
memcpy(mask->mac, wc->dl_src_mask, ETH_ADDR_LEN);
|
||||
break;
|
||||
|
||||
case MFF_VLAN_TCI:
|
||||
@@ -786,9 +788,6 @@ mf_is_mask_valid(const struct mf_field *mf, const union mf_value *mask)
|
||||
return (mf->n_bytes == 4
|
||||
? ip_is_cidr(mask->be32)
|
||||
: ipv6_is_cidr(&mask->ipv6));
|
||||
|
||||
case MFM_MCAST:
|
||||
return flow_wildcards_is_dl_dst_mask_valid(mask->mac);
|
||||
}
|
||||
|
||||
NOT_REACHED();
|
||||
@@ -1532,13 +1531,13 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
|
||||
#endif
|
||||
|
||||
case MFF_ETH_SRC:
|
||||
rule->wc.wildcards |= FWW_DL_SRC;
|
||||
memset(rule->flow.dl_src, 0, sizeof rule->flow.dl_src);
|
||||
memset(rule->flow.dl_src, 0, ETH_ADDR_LEN);
|
||||
memset(rule->wc.dl_src_mask, 0, ETH_ADDR_LEN);
|
||||
break;
|
||||
|
||||
case MFF_ETH_DST:
|
||||
rule->wc.wildcards |= FWW_DL_DST | FWW_ETH_MCAST;
|
||||
memset(rule->flow.dl_dst, 0, sizeof rule->flow.dl_dst);
|
||||
memset(rule->flow.dl_dst, 0, ETH_ADDR_LEN);
|
||||
memset(rule->wc.dl_dst_mask, 0, ETH_ADDR_LEN);
|
||||
break;
|
||||
|
||||
case MFF_ETH_TYPE:
|
||||
@@ -1678,7 +1677,6 @@ mf_set(const struct mf_field *mf,
|
||||
|
||||
switch (mf->id) {
|
||||
case MFF_IN_PORT:
|
||||
case MFF_ETH_SRC:
|
||||
case MFF_ETH_TYPE:
|
||||
case MFF_VLAN_VID:
|
||||
case MFF_VLAN_PCP:
|
||||
@@ -1734,9 +1732,11 @@ mf_set(const struct mf_field *mf,
|
||||
break;
|
||||
|
||||
case MFF_ETH_DST:
|
||||
if (flow_wildcards_is_dl_dst_mask_valid(mask->mac)) {
|
||||
cls_rule_set_dl_dst_masked(rule, value->mac, mask->mac);
|
||||
}
|
||||
break;
|
||||
|
||||
case MFF_ETH_SRC:
|
||||
cls_rule_set_dl_src_masked(rule, value->mac, mask->mac);
|
||||
break;
|
||||
|
||||
case MFF_VLAN_TCI:
|
||||
|
@@ -144,8 +144,7 @@ enum mf_prereqs {
|
||||
enum mf_maskable {
|
||||
MFM_NONE, /* No sub-field masking. */
|
||||
MFM_FULLY, /* Every bit is individually maskable. */
|
||||
MFM_CIDR, /* Contiguous low-order bits may be masked. */
|
||||
MFM_MCAST /* Byte 0, bit 0 is separately maskable. */
|
||||
MFM_CIDR /* Contiguous low-order bits may be masked. */
|
||||
};
|
||||
|
||||
/* How to format or parse a field's value. */
|
||||
|
@@ -354,20 +354,18 @@ nxm_put_eth(struct ofpbuf *b, uint32_t header,
|
||||
}
|
||||
|
||||
static void
|
||||
nxm_put_eth_dst(struct ofpbuf *b,
|
||||
flow_wildcards_t wc, const uint8_t value[ETH_ADDR_LEN])
|
||||
nxm_put_eth_masked(struct ofpbuf *b, uint32_t header,
|
||||
const uint8_t value[ETH_ADDR_LEN],
|
||||
const uint8_t mask[ETH_ADDR_LEN])
|
||||
{
|
||||
switch (wc & (FWW_DL_DST | FWW_ETH_MCAST)) {
|
||||
case FWW_DL_DST | FWW_ETH_MCAST:
|
||||
break;
|
||||
default:
|
||||
nxm_put_header(b, NXM_OF_ETH_DST_W);
|
||||
if (!eth_addr_is_zero(mask)) {
|
||||
if (eth_mask_is_exact(mask)) {
|
||||
nxm_put_eth(b, header, value);
|
||||
} else {
|
||||
nxm_put_header(b, NXM_MAKE_WILD_HEADER(header));
|
||||
ofpbuf_put(b, value, ETH_ADDR_LEN);
|
||||
ofpbuf_put(b, flow_wildcards_to_dl_dst_mask(wc), ETH_ADDR_LEN);
|
||||
break;
|
||||
case 0:
|
||||
nxm_put_eth(b, NXM_OF_ETH_DST, value);
|
||||
break;
|
||||
ofpbuf_put(b, mask, ETH_ADDR_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,7 +469,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr,
|
||||
int match_len;
|
||||
int i;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
/* Metadata. */
|
||||
if (!(wc & FWW_IN_PORT)) {
|
||||
@@ -480,10 +478,8 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr,
|
||||
}
|
||||
|
||||
/* Ethernet. */
|
||||
nxm_put_eth_dst(b, wc, flow->dl_dst);
|
||||
if (!(wc & FWW_DL_SRC)) {
|
||||
nxm_put_eth(b, NXM_OF_ETH_SRC, flow->dl_src);
|
||||
}
|
||||
nxm_put_eth_masked(b, NXM_OF_ETH_SRC, flow->dl_src, cr->wc.dl_src_mask);
|
||||
nxm_put_eth_masked(b, NXM_OF_ETH_DST, flow->dl_dst, cr->wc.dl_dst_mask);
|
||||
if (!(wc & FWW_DL_TYPE)) {
|
||||
nxm_put_16(b, NXM_OF_ETH_TYPE,
|
||||
ofputil_dl_type_to_openflow(flow->dl_type));
|
||||
|
@@ -90,7 +90,7 @@ void nxm_decode(struct mf_subfield *, ovs_be32 header, ovs_be16 ofs_nbits);
|
||||
void nxm_decode_discrete(struct mf_subfield *, ovs_be32 header,
|
||||
ovs_be16 ofs, ovs_be16 n_bits);
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
/* Upper bound on the length of an nx_match. The longest nx_match (an
|
||||
* IPV6 neighbor discovery message using 5 registers) would be:
|
||||
*
|
||||
@@ -98,7 +98,7 @@ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
* ------ ----- ---- -----
|
||||
* NXM_OF_IN_PORT 4 2 -- 6
|
||||
* NXM_OF_ETH_DST_W 4 6 6 16
|
||||
* NXM_OF_ETH_SRC 4 6 -- 10
|
||||
* NXM_OF_ETH_SRC_W 4 6 6 16
|
||||
* NXM_OF_ETH_TYPE 4 2 -- 6
|
||||
* NXM_OF_VLAN_TCI 4 2 2 8
|
||||
* NXM_OF_IP_TOS 4 1 -- 5
|
||||
@@ -123,7 +123,7 @@ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
* NXM_NX_REG_W(7) 4 4 4 12
|
||||
* NXM_NX_TUN_ID_W 4 8 8 20
|
||||
* -------------------------------------------
|
||||
* total 327
|
||||
* total 333
|
||||
*
|
||||
* So this value is conservative.
|
||||
*/
|
||||
|
@@ -76,8 +76,6 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
|
||||
* name. */
|
||||
#define WC_INVARIANT_LIST \
|
||||
WC_INVARIANT_BIT(IN_PORT) \
|
||||
WC_INVARIANT_BIT(DL_SRC) \
|
||||
WC_INVARIANT_BIT(DL_DST) \
|
||||
WC_INVARIANT_BIT(DL_TYPE) \
|
||||
WC_INVARIANT_BIT(NW_PROTO)
|
||||
|
||||
@@ -101,7 +99,7 @@ static const flow_wildcards_t WC_INVARIANTS = 0
|
||||
void
|
||||
ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *wc)
|
||||
{
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
/* Initialize most of rule->wc. */
|
||||
flow_wildcards_init_catchall(wc);
|
||||
@@ -127,11 +125,11 @@ ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *wc)
|
||||
wc->tp_dst_mask = htons(UINT16_MAX);
|
||||
}
|
||||
|
||||
if (ofpfw & OFPFW_DL_DST) {
|
||||
/* OpenFlow 1.0 OFPFW_DL_DST covers the whole Ethernet destination, but
|
||||
* Open vSwitch breaks the Ethernet destination into bits as FWW_DL_DST
|
||||
* and FWW_ETH_MCAST. */
|
||||
wc->wildcards |= FWW_ETH_MCAST;
|
||||
if (!(ofpfw & OFPFW_DL_SRC)) {
|
||||
memset(wc->dl_src_mask, 0xff, ETH_ADDR_LEN);
|
||||
}
|
||||
if (!(ofpfw & OFPFW_DL_DST)) {
|
||||
memset(wc->dl_dst_mask, 0xff, ETH_ADDR_LEN);
|
||||
}
|
||||
|
||||
/* VLAN TCI mask. */
|
||||
@@ -212,6 +210,12 @@ ofputil_cls_rule_to_match(const struct cls_rule *rule, struct ofp_match *match)
|
||||
if (!wc->tp_dst_mask) {
|
||||
ofpfw |= OFPFW_TP_DST;
|
||||
}
|
||||
if (eth_addr_is_zero(wc->dl_src_mask)) {
|
||||
ofpfw |= OFPFW_DL_SRC;
|
||||
}
|
||||
if (eth_addr_is_zero(wc->dl_dst_mask)) {
|
||||
ofpfw |= OFPFW_DL_DST;
|
||||
}
|
||||
|
||||
/* Translate VLANs. */
|
||||
match->dl_vlan = htons(0);
|
||||
@@ -1174,10 +1178,15 @@ ofputil_usable_protocols(const struct cls_rule *rule)
|
||||
{
|
||||
const struct flow_wildcards *wc = &rule->wc;
|
||||
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
|
||||
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
|
||||
|
||||
/* Only NXM supports separately wildcards the Ethernet multicast bit. */
|
||||
if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) {
|
||||
/* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */
|
||||
if (!eth_mask_is_exact(wc->dl_src_mask)
|
||||
&& !eth_addr_is_zero(wc->dl_src_mask)) {
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
if (!eth_mask_is_exact(wc->dl_dst_mask)
|
||||
&& !eth_addr_is_zero(wc->dl_dst_mask)) {
|
||||
return OFPUTIL_P_NXM_ANY;
|
||||
}
|
||||
|
||||
|
@@ -153,7 +153,7 @@ eth_format_masked(const uint8_t eth[ETH_ADDR_LEN],
|
||||
const uint8_t mask[ETH_ADDR_LEN], struct ds *s)
|
||||
{
|
||||
ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth));
|
||||
if (mask) {
|
||||
if (mask && !eth_mask_is_exact(mask)) {
|
||||
ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(mask));
|
||||
}
|
||||
}
|
||||
|
@@ -230,9 +230,12 @@ NXM_OF_ETH_DST_W(000000000000/010000000000)
|
||||
NXM_OF_ETH_DST_W(ffffffffffff/010000000000)
|
||||
NXM_OF_ETH_DST_W(0002e30f80a4/ffffffffffff)
|
||||
NXM_OF_ETH_DST_W(0002e30f80a4/feffffffffff)
|
||||
NXM_OF_ETH_DST_W(60175619848f/5a5a5a5a5a5a)
|
||||
|
||||
# eth src
|
||||
NXM_OF_ETH_SRC(020898456ddb)
|
||||
NXM_OF_ETH_SRC_W(012345abcdef/ffffff555555)
|
||||
NXM_OF_ETH_SRC_W(020898456ddb/ffffffffffff)
|
||||
|
||||
# eth type
|
||||
NXM_OF_ETH_TYPE(0800)
|
||||
@@ -427,9 +430,12 @@ NXM_OF_ETH_DST_W(000000000000/010000000000)
|
||||
NXM_OF_ETH_DST_W(010000000000/010000000000)
|
||||
NXM_OF_ETH_DST(0002e30f80a4)
|
||||
NXM_OF_ETH_DST_W(0002e30f80a4/feffffffffff)
|
||||
NXM_OF_ETH_DST_W(40125218000a/5a5a5a5a5a5a)
|
||||
|
||||
# eth src
|
||||
NXM_OF_ETH_SRC(020898456ddb)
|
||||
NXM_OF_ETH_SRC_W(012345014545/ffffff555555)
|
||||
NXM_OF_ETH_SRC(020898456ddb)
|
||||
|
||||
# eth type
|
||||
NXM_OF_ETH_TYPE(0800)
|
||||
|
@@ -52,8 +52,8 @@
|
||||
CLS_FIELD(FWW_DL_TYPE, dl_type, DL_TYPE) \
|
||||
CLS_FIELD(0, tp_src, TP_SRC) \
|
||||
CLS_FIELD(0, tp_dst, TP_DST) \
|
||||
CLS_FIELD(FWW_DL_SRC, dl_src, DL_SRC) \
|
||||
CLS_FIELD(FWW_DL_DST | FWW_ETH_MCAST, dl_dst, DL_DST) \
|
||||
CLS_FIELD(0, dl_src, DL_SRC) \
|
||||
CLS_FIELD(0, dl_dst, DL_DST) \
|
||||
CLS_FIELD(FWW_NW_PROTO, nw_proto, NW_PROTO) \
|
||||
CLS_FIELD(FWW_NW_DSCP, nw_tos, NW_DSCP)
|
||||
|
||||
@@ -202,6 +202,12 @@ match(const struct cls_rule *wild, const struct flow *fixed)
|
||||
eq = !((fixed->tp_src ^ wild->flow.tp_src) & wild->wc.tp_src_mask);
|
||||
} else if (f_idx == CLS_F_IDX_TP_DST) {
|
||||
eq = !((fixed->tp_dst ^ wild->flow.tp_dst) & wild->wc.tp_dst_mask);
|
||||
} else if (f_idx == CLS_F_IDX_DL_SRC) {
|
||||
eq = !eth_addr_equal_except(fixed->dl_src, wild->flow.dl_src,
|
||||
wild->wc.dl_src_mask);
|
||||
} else if (f_idx == CLS_F_IDX_DL_DST) {
|
||||
eq = !eth_addr_equal_except(fixed->dl_dst, wild->flow.dl_dst,
|
||||
wild->wc.dl_dst_mask);
|
||||
} else if (f_idx == CLS_F_IDX_VLAN_TCI) {
|
||||
eq = !((fixed->vlan_tci ^ wild->flow.vlan_tci)
|
||||
& wild->wc.vlan_tci_mask);
|
||||
@@ -471,6 +477,10 @@ make_rule(int wc_fields, unsigned int priority, int value_pat)
|
||||
rule->cls_rule.wc.tp_src_mask = htons(UINT16_MAX);
|
||||
} else if (f_idx == CLS_F_IDX_TP_DST) {
|
||||
rule->cls_rule.wc.tp_dst_mask = htons(UINT16_MAX);
|
||||
} else if (f_idx == CLS_F_IDX_DL_SRC) {
|
||||
memset(rule->cls_rule.wc.dl_src_mask, 0xff, ETH_ADDR_LEN);
|
||||
} else if (f_idx == CLS_F_IDX_DL_DST) {
|
||||
memset(rule->cls_rule.wc.dl_dst_mask, 0xff, ETH_ADDR_LEN);
|
||||
} else if (f_idx == CLS_F_IDX_VLAN_TCI) {
|
||||
rule->cls_rule.wc.vlan_tci_mask = htons(UINT16_MAX);
|
||||
} else if (f_idx == CLS_F_IDX_TUN_ID) {
|
||||
|
@@ -381,11 +381,13 @@ Matches an Ethernet source (or destination) address specified as 6
|
||||
pairs of hexadecimal digits delimited by colons
|
||||
(e.g. \fB00:0A:E4:25:6B:B0\fR).
|
||||
.
|
||||
.IP \fBdl_dst=\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB/\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR
|
||||
.IP \fBdl_src=\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB/\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR
|
||||
.IQ \fBdl_dst=\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB/\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR
|
||||
Matches an Ethernet destination address specified as 6 pairs of
|
||||
hexadecimal digits delimited by colons (e.g. \fB00:0A:E4:25:6B:B0\fR),
|
||||
with a wildcard mask following the slash. Only
|
||||
the following masks are allowed:
|
||||
with a wildcard mask following the slash. Open vSwitch 1.8 and later
|
||||
support arbitrary masks for source and/or destination. Earlier
|
||||
versions only support masking the destination with the following masks:
|
||||
.RS
|
||||
.IP \fB01:00:00:00:00:00\fR
|
||||
Match only the multicast bit. Thus,
|
||||
|
Reference in New Issue
Block a user