}
}
+static void
+str_to_eth_dst(const char *str,
+ uint8_t mac[ETH_ADDR_LEN], uint8_t mask[ETH_ADDR_LEN])
+{
+ if (sscanf(str, ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT,
+ ETH_ADDR_SCAN_ARGS(mac), ETH_ADDR_SCAN_ARGS(mask))
+ == ETH_ADDR_SCAN_COUNT * 2) {
+ if (!flow_wildcards_is_dl_dst_mask_valid(mask)) {
+ ovs_fatal(0, "%s: invalid Ethernet destination mask (only "
+ "00:00:00:00:00:00, 01:00:00:00:00:00, "
+ "fe:ff:ff:ff:ff:ff, and ff:ff:ff:ff:ff:ff are allowed)",
+ str);
+ }
+ } else if (sscanf(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
+ == ETH_ADDR_SCAN_COUNT) {
+ memset(mask, 0xff, ETH_ADDR_LEN);
+ } else {
+ ovs_fatal(0, "invalid mac address %s", str);
+ }
+}
+
static void
str_to_ip(const char *str_, ovs_be32 *ip, ovs_be32 *maskp)
{
nast->subtype = htons(NXAST_SET_TUNNEL);
nast->tun_id = htonl(tun_id);
}
- } else if (!strcasecmp(act, "drop_spoofed_arp")) {
- struct nx_action_header *nah;
- nah = put_action(b, sizeof *nah, OFPAT_VENDOR);
- nah->vendor = htonl(NX_VENDOR_ID);
- nah->subtype = htons(NXAST_DROP_SPOOFED_ARP);
} else if (!strcasecmp(act, "set_queue")) {
struct nx_action_set_queue *nasq;
nasq = put_action(b, sizeof *nasq, OFPAT_VENDOR);
FIELD(F_DL_VLAN, "dl_vlan", 0) \
FIELD(F_DL_VLAN_PCP, "dl_vlan_pcp", 0) \
FIELD(F_DL_SRC, "dl_src", FWW_DL_SRC) \
- FIELD(F_DL_DST, "dl_dst", FWW_DL_DST) \
+ FIELD(F_DL_DST, "dl_dst", FWW_DL_DST | FWW_ETH_MCAST) \
FIELD(F_DL_TYPE, "dl_type", FWW_DL_TYPE) \
FIELD(F_NW_SRC, "nw_src", 0) \
FIELD(F_NW_DST, "nw_dst", 0) \
parse_field_value(struct cls_rule *rule, enum field_index index,
const char *value)
{
- uint8_t mac[ETH_ADDR_LEN];
+ uint8_t mac[ETH_ADDR_LEN], mac_mask[ETH_ADDR_LEN];
ovs_be64 tun_id, tun_mask;
ovs_be32 ip, mask;
struct in6_addr ipv6, ipv6_mask;
break;
case F_DL_DST:
- str_to_mac(value, mac);
- cls_rule_set_dl_dst(rule, mac);
+ str_to_eth_dst(value, mac, mac_mask);
+ cls_rule_set_dl_dst_masked(rule, mac, mac_mask);
break;
case F_DL_TYPE:
{
bool is_del = command == OFPFC_DELETE || command == OFPFC_DELETE_STRICT;
enum nx_flow_format min_format, next_format;
+ struct cls_rule rule_copy;
struct ofpbuf actions;
struct ofpbuf *ofm;
struct flow_mod fm;
*cur_format = next_format;
}
+ /* Normalize a copy of the rule. This ensures that non-normalized flows
+ * get logged but doesn't affect what gets sent to the switch, so that the
+ * switch can do whatever it likes with the flow. */
+ rule_copy = fm.cr;
+ ofputil_normalize_rule(&rule_copy, next_format);
+
if (fm.table_id != 0xff && !*flow_mod_table_id) {
struct ofpbuf *sff = ofputil_make_flow_mod_table_id(true);
list_push_back(packets, &sff->list_node);