diff options
-rw-r--r-- | datapath/flow.c | 6 | ||||
-rw-r--r-- | datapath/flow.h | 2 | ||||
-rw-r--r-- | include/openflow/nicira-ext.h | 19 | ||||
-rw-r--r-- | include/openvswitch/datapath-protocol.h | 2 | ||||
-rw-r--r-- | lib/classifier.c | 38 | ||||
-rw-r--r-- | lib/classifier.h | 2 | ||||
-rw-r--r-- | lib/flow.c | 18 | ||||
-rw-r--r-- | lib/flow.h | 15 | ||||
-rw-r--r-- | lib/nx-match.c | 21 | ||||
-rw-r--r-- | lib/nx-match.def | 2 | ||||
-rw-r--r-- | lib/odp-util.c | 10 | ||||
-rw-r--r-- | lib/ofp-parse.c | 14 | ||||
-rw-r--r-- | lib/ofp-util.c | 9 | ||||
-rw-r--r-- | tests/ovs-ofctl.at | 32 | ||||
-rw-r--r-- | utilities/ovs-ofctl.8.in | 14 |
15 files changed, 177 insertions, 27 deletions
diff --git a/datapath/flow.c b/datapath/flow.c index eb67cf45..d83c17d9 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -390,6 +390,8 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, || key->nw_proto == ARPOP_REPLY) { memcpy(&key->nw_src, arp->ar_sip, sizeof(key->nw_src)); memcpy(&key->nw_dst, arp->ar_tip, sizeof(key->nw_dst)); + memcpy(key->arp_sha, arp->ar_sha, ETH_ALEN); + memcpy(key->arp_tha, arp->ar_tha, ETH_ALEN); } } } @@ -538,6 +540,8 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *attr) if (arp_key->arp_op & htons(0xff00)) return -EINVAL; swkey->nw_proto = ntohs(arp_key->arp_op); + memcpy(swkey->arp_sha, arp_key->arp_sha, ETH_ALEN); + memcpy(swkey->arp_tha, arp_key->arp_tha, ETH_ALEN); break; default: @@ -665,6 +669,8 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) arp_key->arp_sip = swkey->nw_src; arp_key->arp_tip = swkey->nw_dst; arp_key->arp_op = htons(swkey->nw_proto); + memcpy(arp_key->arp_sha, swkey->arp_sha, ETH_ALEN); + memcpy(arp_key->arp_tha, swkey->arp_tha, ETH_ALEN); } return 0; diff --git a/datapath/flow.h b/datapath/flow.h index be734532..b9af2722 100644 --- a/datapath/flow.h +++ b/datapath/flow.h @@ -42,6 +42,8 @@ struct sw_flow_key { u8 dl_dst[ETH_ALEN]; /* Ethernet destination address. */ u8 nw_proto; /* IP protocol or lower 8 bits of ARP opcode. */ u8 nw_tos; /* IP ToS (DSCP field, 6 bits). */ + u8 arp_sha[ETH_ALEN]; /* ARP source hardware address. */ + u8 arp_tha[ETH_ALEN]; /* ARP target hardware address. */ }; struct sw_flow { diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 5013a5a0..c5b0a7ca 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -312,9 +312,9 @@ OFP_ASSERT(sizeof(struct nx_action_set_tunnel64) == 24); * Ethernet+IPv4 ARP packet for which the source Ethernet address inside the * ARP packet differs from the source Ethernet address in the Ethernet header. * - * This is useful because OpenFlow does not provide a way to match on the - * Ethernet addresses inside ARP packets, so there is no other way to drop - * spoofed ARPs other than sending every ARP packet to a controller. */ + * (This action is deprecated in favor of defining flows using the + * NXM_NX_ARP_SHA flow match and will likely be removed in a future version + * of Open vSwitch.) */ struct nx_action_drop_spoofed_arp { ovs_be16 type; /* OFPAT_VENDOR. */ ovs_be16 len; /* Length is 16. */ @@ -386,6 +386,8 @@ OFP_ASSERT(sizeof(struct nx_action_pop_queue) == 16); * - NXM_OF_ARP_SPA * - NXM_OF_ARP_TPA * - NXM_NX_TUN_ID + * - NXM_NX_ARP_SHA + * - NXM_NX_ARP_THA * - NXM_NX_REG(idx) for idx in the switch's accepted range. * * The following nxm_header values are potentially acceptable as 'dst': @@ -1038,6 +1040,17 @@ enum nx_mp_algorithm { #define NXM_NX_TUN_ID NXM_HEADER (0x0001, 16, 8) #define NXM_NX_TUN_ID_W NXM_HEADER_W(0x0001, 16, 8) +/* For an Ethernet+IP ARP packet, the source or target hardware address + * in the ARP header. Always 0 otherwise. + * + * Prereqs: NXM_OF_ETH_TYPE must match 0x0806 exactly. + * + * Format: 48-bit Ethernet MAC address. + * + * Masking: Not maskable. */ +#define NXM_NX_ARP_SHA NXM_HEADER (0x0001, 17, 6) +#define NXM_NX_ARP_THA NXM_HEADER (0x0001, 18, 6) + /* ## --------------------- ## */ /* ## Requests and replies. ## */ /* ## --------------------- ## */ diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h index 1fb0bf99..fdd225db 100644 --- a/include/openvswitch/datapath-protocol.h +++ b/include/openvswitch/datapath-protocol.h @@ -356,6 +356,8 @@ struct odp_key_arp { ovs_be32 arp_sip; ovs_be32 arp_tip; ovs_be16 arp_op; + uint8_t arp_sha[6]; + uint8_t arp_tha[6]; }; /** diff --git a/lib/classifier.c b/lib/classifier.c index 53280e50..a4532a61 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -319,6 +319,20 @@ cls_rule_set_icmp_code(struct cls_rule *rule, uint8_t icmp_code) rule->flow.icmp_code = htons(icmp_code); } +void +cls_rule_set_arp_sha(struct cls_rule *rule, const uint8_t sha[ETH_ADDR_LEN]) +{ + rule->wc.wildcards &= ~FWW_ARP_SHA; + memcpy(rule->flow.arp_sha, sha, ETH_ADDR_LEN); +} + +void +cls_rule_set_arp_tha(struct cls_rule *rule, const uint8_t tha[ETH_ADDR_LEN]) +{ + rule->wc.wildcards &= ~FWW_ARP_THA; + memcpy(rule->flow.arp_tha, tha, ETH_ADDR_LEN); +} + /* Returns true if 'a' and 'b' have the same priority, wildcard the same * fields, and have the same values for fixed fields, otherwise false. */ bool @@ -467,6 +481,16 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s) ds_put_format(s, "nw_proto=%"PRIu8",", f->nw_proto); } } + if (f->dl_type == htons(ETH_TYPE_ARP)) { + if (!(w & FWW_ARP_SHA)) { + ds_put_format(s, "arp_sha="ETH_ADDR_FMT",", + ETH_ADDR_ARGS(f->arp_sha)); + } + if (!(w & FWW_ARP_THA)) { + ds_put_format(s, "arp_tha="ETH_ADDR_FMT",", + ETH_ADDR_ARGS(f->arp_tha)); + } + } if (!(w & FWW_NW_TOS)) { ds_put_format(s, "nw_tos=%"PRIu8",", f->nw_tos); } @@ -947,7 +971,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_SIG_SIZE == 40 + FLOW_N_REGS * 4); + BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 52 + FLOW_N_REGS * 4); for (i = 0; i < FLOW_N_REGS; i++) { if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) { @@ -974,7 +998,9 @@ flow_equal_except(const struct flow *a, const struct flow *b, && (wc & FWW_ETH_MCAST || !((a->dl_dst[0] ^ b->dl_dst[0]) & 0x01)) && (wc & FWW_NW_PROTO || a->nw_proto == b->nw_proto) - && (wc & FWW_NW_TOS || a->nw_tos == b->nw_tos)); + && (wc & FWW_NW_TOS || a->nw_tos == b->nw_tos) + && (wc & FWW_ARP_SHA || eth_addr_equals(a->arp_sha, b->arp_sha)) + && (wc & FWW_ARP_THA || eth_addr_equals(a->arp_tha, b->arp_tha))); } static void @@ -983,7 +1009,7 @@ zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards) const flow_wildcards_t wc = wildcards->wildcards; int i; - BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 40 + 4 * FLOW_N_REGS); + BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 52 + 4 * FLOW_N_REGS); for (i = 0; i < FLOW_N_REGS; i++) { flow->regs[i] &= wildcards->reg_masks[i]; @@ -1020,4 +1046,10 @@ zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards) if (wc & FWW_NW_TOS) { flow->nw_tos = 0; } + if (wc & FWW_ARP_SHA) { + memset(flow->arp_sha, 0, sizeof flow->arp_sha); + } + if (wc & FWW_ARP_THA) { + memset(flow->arp_tha, 0, sizeof flow->arp_tha); + } } diff --git a/lib/classifier.h b/lib/classifier.h index 7b347e7b..40149727 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -101,6 +101,8 @@ bool cls_rule_set_nw_dst_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask); void cls_rule_set_nw_tos(struct cls_rule *, uint8_t); void cls_rule_set_icmp_type(struct cls_rule *, uint8_t); void cls_rule_set_icmp_code(struct cls_rule *, uint8_t); +void cls_rule_set_arp_sha(struct cls_rule *, const uint8_t[6]); +void cls_rule_set_arp_tha(struct cls_rule *, const uint8_t[6]); bool cls_rule_equal(const struct cls_rule *, const struct cls_rule *); @@ -224,6 +224,8 @@ flow_extract(struct ofpbuf *packet, ovs_be64 tun_id, uint16_t in_port, || (flow->nw_proto == ARP_OP_REPLY)) { flow->nw_src = arp->ar_spa; flow->nw_dst = arp->ar_tpa; + memcpy(flow->arp_sha, arp->ar_sha, ETH_ADDR_LEN); + memcpy(flow->arp_tha, arp->ar_tha, ETH_ADDR_LEN); } } } @@ -274,17 +276,23 @@ flow_format(struct ds *ds, const struct flow *flow) " type%04"PRIx16 " proto%"PRIu8 " tos%"PRIu8 - " ip"IP_FMT"->"IP_FMT - " port%"PRIu16"->%"PRIu16, + " ip"IP_FMT"->"IP_FMT, ETH_ADDR_ARGS(flow->dl_src), ETH_ADDR_ARGS(flow->dl_dst), ntohs(flow->dl_type), flow->nw_proto, flow->nw_tos, IP_ARGS(&flow->nw_src), - IP_ARGS(&flow->nw_dst), - ntohs(flow->tp_src), - ntohs(flow->tp_dst)); + IP_ARGS(&flow->nw_dst)); + if (flow->tp_src || flow->tp_dst) { + ds_put_format(ds, " port%"PRIu16"->%"PRIu16, + ntohs(flow->tp_src), ntohs(flow->tp_dst)); + } + if (!eth_addr_is_zero(flow->arp_sha) || !eth_addr_is_zero(flow->arp_tha)) { + ds_put_format(ds, " arp_ha"ETH_ADDR_FMT"->"ETH_ADDR_FMT, + ETH_ADDR_ARGS(flow->arp_sha), + ETH_ADDR_ARGS(flow->arp_tha)); + } } void @@ -54,14 +54,17 @@ struct flow { uint8_t dl_dst[6]; /* Ethernet destination address. */ uint8_t nw_proto; /* IP protocol or low 8 bits of ARP opcode. */ uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */ + uint8_t arp_sha[6]; /* ARP source hardware address. */ + uint8_t arp_tha[6]; /* ARP target hardware address. */ + uint32_t reserved; /* Reserved for 64-bit packing. */ }; /* Assert that there are FLOW_SIG_SIZE bytes of significant data in "struct * flow", followed by FLOW_PAD_SIZE bytes of padding. */ -#define FLOW_SIG_SIZE (40 + FLOW_N_REGS * 4) -#define FLOW_PAD_SIZE 0 -BUILD_ASSERT_DECL(offsetof(struct flow, nw_tos) == FLOW_SIG_SIZE - 1); -BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nw_tos) == 1); +#define FLOW_SIG_SIZE (52 + FLOW_N_REGS * 4) +#define FLOW_PAD_SIZE 4 +BUILD_ASSERT_DECL(offsetof(struct flow, arp_tha) == FLOW_SIG_SIZE - 6); +BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->arp_tha) == 6); BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE); int flow_extract(struct ofpbuf *, uint64_t tun_id, uint16_t in_port, @@ -115,7 +118,9 @@ typedef unsigned int OVS_BITWISE flow_wildcards_t; /* No corresponding OFPFW_* or OVSFW_* bits. */ #define FWW_ETH_MCAST ((OVS_FORCE flow_wildcards_t) (1 << 8)) /* multicast bit only */ -#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 9)) - 1)) +#define FWW_ARP_SHA ((OVS_FORCE flow_wildcards_t) (1 << 9)) +#define FWW_ARP_THA ((OVS_FORCE flow_wildcards_t) (1 << 10)) +#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 11)) - 1)) /* Information on wildcards for a flow, as a supplement to "struct flow". * diff --git a/lib/nx-match.c b/lib/nx-match.c index 7326b114..d43372b8 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -318,6 +318,13 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f, return 0; } + case NFI_NXM_NX_ARP_SHA: + memcpy(flow->arp_sha, value, ETH_ADDR_LEN); + return 0; + case NFI_NXM_NX_ARP_THA: + memcpy(flow->arp_tha, value, ETH_ADDR_LEN); + return 0; + /* Tunnel ID. */ case NFI_NXM_NX_TUN_ID: if (wc->tun_id_mask) { @@ -693,6 +700,12 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr) } nxm_put_32m(b, NXM_OF_ARP_SPA, flow->nw_src, cr->wc.nw_src_mask); nxm_put_32m(b, NXM_OF_ARP_TPA, flow->nw_dst, cr->wc.nw_dst_mask); + if (!(wc & FWW_ARP_SHA)) { + nxm_put_eth(b, NXM_NX_ARP_SHA, flow->arp_sha); + } + if (!(wc & FWW_ARP_THA)) { + nxm_put_eth(b, NXM_NX_ARP_THA, flow->arp_tha); + } } /* Tunnel ID. */ @@ -1162,6 +1175,12 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow) #error #endif + case NFI_NXM_NX_ARP_SHA: + return eth_addr_to_uint64(flow->arp_sha); + + case NFI_NXM_NX_ARP_THA: + return eth_addr_to_uint64(flow->arp_tha); + case NFI_NXM_NX_TUN_ID_W: case NFI_NXM_OF_ETH_DST_W: case NFI_NXM_OF_VLAN_TCI_W: @@ -1234,6 +1253,8 @@ nxm_write_field(const struct nxm_field *dst, struct flow *flow, case NFI_NXM_OF_IP_DST_W: case NFI_NXM_OF_ARP_SPA_W: case NFI_NXM_OF_ARP_TPA_W: + case NFI_NXM_NX_ARP_SHA: + case NFI_NXM_NX_ARP_THA: case N_NXM_FIELDS: NOT_REACHED(); } diff --git a/lib/nx-match.def b/lib/nx-match.def index d3e240ed..966143dc 100644 --- a/lib/nx-match.def +++ b/lib/nx-match.def @@ -39,6 +39,8 @@ DEFINE_FIELD (OF_ARP_OP, FWW_NW_PROTO, ETH_TYPE_ARP, 0, false) DEFINE_FIELD_M(OF_ARP_SPA, 0, ETH_TYPE_ARP, 0, false) DEFINE_FIELD_M(OF_ARP_TPA, 0, ETH_TYPE_ARP, 0, false) DEFINE_FIELD_M(NX_TUN_ID, 0, 0, 0, true) +DEFINE_FIELD (NX_ARP_SHA, FWW_ARP_SHA, ETH_TYPE_ARP, 0, false) +DEFINE_FIELD (NX_ARP_THA, FWW_ARP_THA, ETH_TYPE_ARP, 0, false) DEFINE_FIELD_M(NX_REG0, 0, 0, 0, true) #if FLOW_N_REGS >= 2 diff --git a/lib/odp-util.c b/lib/odp-util.c index 5f1a77ce..bacb1c04 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -307,9 +307,11 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) case ODP_KEY_ATTR_ARP: arp_key = nl_attr_get(a); - ds_put_format(ds, "arp(sip="IP_FMT",tip="IP_FMT",op=%"PRIu16")", + ds_put_format(ds, "arp(sip="IP_FMT",tip="IP_FMT",op=%"PRIu16"," + "sha="ETH_ADDR_FMT",tha="ETH_ADDR_FMT")", IP_ARGS(&arp_key->arp_sip), IP_ARGS(&arp_key->arp_tip), - ntohs(arp_key->arp_op)); + ntohs(arp_key->arp_op), ETH_ADDR_ARGS(arp_key->arp_sha), + ETH_ADDR_ARGS(arp_key->arp_tha)); break; default: @@ -416,6 +418,8 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow) arp_key->arp_sip = flow->nw_src; arp_key->arp_tip = flow->nw_dst; arp_key->arp_op = htons(flow->nw_proto); + memcpy(arp_key->arp_sha, flow->arp_sha, ETH_ADDR_LEN); + memcpy(arp_key->arp_tha, flow->arp_tha, ETH_ADDR_LEN); } } @@ -541,6 +545,8 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len, return EINVAL; } flow->nw_proto = ntohs(arp_key->arp_op); + memcpy(flow->arp_sha, arp_key->arp_sha, ETH_ADDR_LEN); + memcpy(flow->arp_tha, arp_key->arp_tha, ETH_ADDR_LEN); break; default: diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 65d7a654..366664e3 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -491,7 +491,9 @@ parse_protocol(const char *name, const struct protocol **p_out) FIELD(F_TP_SRC, "tp_src", FWW_TP_SRC) \ FIELD(F_TP_DST, "tp_dst", FWW_TP_DST) \ FIELD(F_ICMP_TYPE, "icmp_type", FWW_TP_SRC) \ - FIELD(F_ICMP_CODE, "icmp_code", FWW_TP_DST) + FIELD(F_ICMP_CODE, "icmp_code", FWW_TP_DST) \ + FIELD(F_ARP_SHA, "arp_sha", FWW_ARP_SHA) \ + FIELD(F_ARP_THA, "arp_tha", FWW_ARP_THA) enum field_index { #define FIELD(ENUM, NAME, WILDCARD) ENUM, @@ -607,6 +609,16 @@ parse_field_value(struct cls_rule *rule, enum field_index index, cls_rule_set_icmp_code(rule, str_to_u32(value)); break; + case F_ARP_SHA: + str_to_mac(value, mac); + cls_rule_set_arp_sha(rule, mac); + break; + + case F_ARP_THA: + str_to_mac(value, mac); + cls_rule_set_arp_tha(rule, mac); + break; + case N_FIELDS: NOT_REACHED(); } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 925f45fd..59a5fc43 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -124,6 +124,10 @@ ofputil_cls_rule_from_match(const struct ofp_match *match, /* Initialize most of rule->wc. */ flow_wildcards_init_catchall(wc); wc->wildcards = ofpfw & WC_INVARIANTS; + + /* Wildcard fields that aren't defined by ofp_match or tun_id. */ + wc->wildcards |= (FWW_ARP_SHA | FWW_ARP_THA); + if (ofpfw & OFPFW_NW_TOS) { wc->wildcards |= FWW_NW_TOS; } @@ -859,6 +863,11 @@ is_nxm_required(const struct cls_rule *rule, bool cookie_support, return true; } + /* Only NXM supports matching ARP hardware addresses. */ + if (!(wc->wildcards & FWW_ARP_SHA) || !(wc->wildcards & FWW_ARP_THA)) { + return true; + } + /* Only NXM supports matching registers. */ if (!regs_fully_wildcarded(wc)) { return true; diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 0648f067..7eecf287 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -61,6 +61,7 @@ AT_DATA([flows.txt], [ tcp,tp_src=123,actions=flood in_port=LOCAL dl_vlan=9 dl_src=00:0A:E4:25:6B:B0 actions=drop arp,nw_src=192.168.0.1 actions=drop_spoofed_arp,NORMAL +arp,dl_src=00:0A:E4:25:6B:B0,arp_sha=00:0A:E4:25:6B:B0 actions=drop udp dl_vlan_pcp=7 idle_timeout=5 actions=strip_vlan output:0 tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1 udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1 @@ -75,6 +76,7 @@ AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl NXT_FLOW_MOD: ADD tcp,tp_src=123 actions=FLOOD NXT_FLOW_MOD: ADD in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0 actions=drop NXT_FLOW_MOD: ADD arp,nw_src=192.168.0.1 actions=drop_spoofed_arp,NORMAL +NXT_FLOW_MOD: ADD arp,dl_src=00:0a:e4:25:6b:b0,arp_sha=00:0a:e4:25:6b:b0 actions=drop NXT_FLOW_MOD: ADD udp,dl_vlan_pcp=7 idle:5 actions=strip_vlan,output:0 NXT_FLOW_MOD: ADD tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1 NXT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1 @@ -92,6 +94,7 @@ AT_DATA([flows.txt], [[ tcp,tp_src=123,actions=flood in_port=LOCAL dl_vlan=9 dl_src=00:0A:E4:25:6B:B0 actions=drop arp,nw_src=192.168.0.1 actions=drop_spoofed_arp,NORMAL +arp,dl_src=00:0A:E4:25:6B:B0,arp_sha=00:0A:E4:25:6B:B0 actions=drop udp dl_vlan_pcp=7 idle_timeout=5 actions=strip_vlan output:0 tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1 udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1 @@ -106,6 +109,7 @@ AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [[NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC(007b) actions=FLOOD NXT_FLOW_MOD: ADD NXM_OF_IN_PORT(fffe), NXM_OF_ETH_SRC(000ae4256bb0), NXM_OF_VLAN_TCI_W(1009/1fff) actions=drop NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_SPA(c0a80001) actions=drop_spoofed_arp,NORMAL +NXT_FLOW_MOD: ADD NXM_OF_ETH_SRC(000ae4256bb0), NXM_OF_ETH_TYPE(0806), NXM_NX_ARP_SHA(000ae4256bb0) actions=drop NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_VLAN_TCI_W(f000/f000), NXM_OF_IP_PROTO(11) idle:5 actions=strip_vlan,output:0 NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_IP_SRC(c0a80003), NXM_OF_IP_PROTO(06), NXM_OF_TCP_DST(0050) actions=set_queue:37,output:1 NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_IP_SRC(c0a80003), NXM_OF_IP_PROTO(11), NXM_OF_UDP_DST(0035) actions=pop_queue,output:1 @@ -205,18 +209,28 @@ NXM_OF_ETH_TYPE(0000) NXM_OF_ARP_OP(0001) NXM_OF_ARP_OP(0001) NXM_OF_ETH_TYPE(0806) NXM_OF_ARP_OP(0001) NXM_OF_ARP_OP(0001) -# ARP source +# ARP source protocol address NXM_OF_ETH_TYPE(0806) NXM_OF_ARP_SPA(ac100014) NXM_OF_ETH_TYPE(0806) NXM_OF_ARP_SPA_W(C0a81234/FFFFFF00) NXM_OF_ETH_TYPE(0800) NXM_OF_ARP_SPA(ac100014) NXM_OF_ARP_SPA_W(C0D8fedc/FFFF0000) -# ARP destination +# ARP destination protocol address NXM_OF_ETH_TYPE(0806) NXM_OF_ARP_TPA(ac100014) NXM_OF_ETH_TYPE(0806) NXM_OF_ARP_TPA_W(C0a812fe/FFFFFF00) NXM_OF_ETH_TYPE(0800) NXM_OF_ARP_TPA(ac100014) NXM_OF_ARP_TPA_W(C0D80000/FFFF0000) +# ARP source hardware address +NXM_OF_ETH_TYPE(0806) NXM_NX_ARP_SHA(0002e30f80a4) +NXM_OF_ETH_TYPE(0800) NXM_NX_ARP_SHA(0002e30f80a4) +NXM_NX_ARP_SHA(0002e30f80a4) + +# ARP destination hardware address +NXM_OF_ETH_TYPE(0806) NXM_NX_ARP_THA(0002e30f80a4) +NXM_OF_ETH_TYPE(0800) NXM_NX_ARP_THA(0002e30f80a4) +NXM_NX_ARP_THA(0002e30f80a4) + # Tunnel ID. NXM_NX_TUN_ID(00000000abcdef01) NXM_NX_TUN_ID_W(84200000abcdef01/84200000FFFFFFFF) @@ -323,18 +337,28 @@ nx_pull_match() returned error 44010104 nx_pull_match() returned error 44010104 nx_pull_match() returned error 44010105 -# ARP source +# ARP source protocol address NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_SPA(ac100014) NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_SPA_W(c0a81200/ffffff00) nx_pull_match() returned error 44010104 nx_pull_match() returned error 44010104 -# ARP destination +# ARP destination protocol address NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_TPA(ac100014) NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_TPA_W(c0a81200/ffffff00) nx_pull_match() returned error 44010104 nx_pull_match() returned error 44010104 +# ARP source hardware address +NXM_OF_ETH_TYPE(0806), NXM_NX_ARP_SHA(0002e30f80a4) +nx_pull_match() returned error 44010104 +nx_pull_match() returned error 44010104 + +# ARP destination hardware address +NXM_OF_ETH_TYPE(0806), NXM_NX_ARP_THA(0002e30f80a4) +nx_pull_match() returned error 44010104 +nx_pull_match() returned error 44010104 + # Tunnel ID. NXM_NX_TUN_ID(00000000abcdef01) NXM_NX_TUN_ID_W(84200000abcdef01/84200000ffffffff) diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index d83a50be..135e705c 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -345,6 +345,12 @@ Extended Match) extension to OpenFlow. When one of these is specified, extension. If the switch does not support NXM, then \fBovs\-ofctl\fR will report a fatal error. . +.IP \fBarp_sha=\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR +.IQ \fBarp_tha=\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR +When \fBdl_type\fR specifies ARP, \fBarp_sha\fR and \fBarp_tha\fR match +the source and target hardware address, respectively. An address is +specified as 6 pairs of hexadecimal digits delimited by colons. +. .IP \fBtun_id=\fItunnel-id\fR[\fB/\fImask\fR] Matches tunnel identifier \fItunnel-id\fR. Only packets that arrive over a tunnel that carries a key (e.g. GRE with the RFC 2890 key @@ -506,10 +512,10 @@ Stops processing further actions, if the packet being processed is an Ethernet+IPv4 ARP packet for which the source Ethernet address inside the ARP packet differs from the source Ethernet address in the Ethernet header. -. -This is useful because OpenFlow does not provide a way to match on the -Ethernet addresses inside ARP packets, so there is no other way to -drop spoofed ARPs other than sending every ARP packet to a controller. +.IP +This action is deprecated in favor of defining flows using the +\fBarp_sha\fR match field described earlier and will likely be removed +in a future version of Open vSwitch. . .IP \fBset_queue\fB:\fIqueue\fR Sets the queue that should be used to \fIqueue\fR when packets are |