summaryrefslogtreecommitdiff
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c64
1 files changed, 32 insertions, 32 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 9a9a5cf36a4b..1b998aa481f8 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -272,25 +272,22 @@ static void macvlan_broadcast(struct sk_buff *skb,
if (skb->protocol == htons(ETH_P_PAUSE))
return;
- for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
- hlist_for_each_entry_rcu(vlan, &port->vlan_hash[i], hlist) {
- if (vlan->dev == src || !(vlan->mode & mode))
- continue;
+ hash_for_each_rcu(port->vlan_hash, i, vlan, hlist) {
+ if (vlan->dev == src || !(vlan->mode & mode))
+ continue;
- hash = mc_hash(vlan, eth->h_dest);
- if (!test_bit(hash, vlan->mc_filter))
- continue;
+ hash = mc_hash(vlan, eth->h_dest);
+ if (!test_bit(hash, vlan->mc_filter))
+ continue;
- err = NET_RX_DROP;
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (likely(nskb))
- err = macvlan_broadcast_one(
- nskb, vlan, eth,
+ err = NET_RX_DROP;
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (likely(nskb))
+ err = macvlan_broadcast_one(nskb, vlan, eth,
mode == MACVLAN_MODE_BRIDGE) ?:
- netif_rx_ni(nskb);
- macvlan_count_rx(vlan, skb->len + ETH_HLEN,
- err == NET_RX_SUCCESS, true);
- }
+ netif_rx_ni(nskb);
+ macvlan_count_rx(vlan, skb->len + ETH_HLEN,
+ err == NET_RX_SUCCESS, true);
}
}
@@ -380,20 +377,14 @@ err:
static void macvlan_flush_sources(struct macvlan_port *port,
struct macvlan_dev *vlan)
{
+ struct macvlan_source_entry *entry;
+ struct hlist_node *next;
int i;
- for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
- struct hlist_node *h, *n;
-
- hlist_for_each_safe(h, n, &port->vlan_source_hash[i]) {
- struct macvlan_source_entry *entry;
+ hash_for_each_safe(port->vlan_source_hash, i, next, entry, hlist)
+ if (entry->vlan == vlan)
+ macvlan_hash_del_source(entry);
- entry = hlist_entry(h, struct macvlan_source_entry,
- hlist);
- if (entry->vlan == vlan)
- macvlan_hash_del_source(entry);
- }
- }
vlan->macaddr_count = 0;
}
@@ -423,18 +414,24 @@ static void macvlan_forward_source_one(struct sk_buff *skb,
macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false);
}
-static void macvlan_forward_source(struct sk_buff *skb,
+static bool macvlan_forward_source(struct sk_buff *skb,
struct macvlan_port *port,
const unsigned char *addr)
{
struct macvlan_source_entry *entry;
u32 idx = macvlan_eth_hash(addr);
struct hlist_head *h = &port->vlan_source_hash[idx];
+ bool consume = false;
hlist_for_each_entry_rcu(entry, h, hlist) {
- if (ether_addr_equal_64bits(entry->addr, addr))
+ if (ether_addr_equal_64bits(entry->addr, addr)) {
+ if (entry->vlan->flags & MACVLAN_FLAG_NODST)
+ consume = true;
macvlan_forward_source_one(skb, entry->vlan);
+ }
}
+
+ return consume;
}
/* called under rcu_read_lock() from netif_receive_skb */
@@ -463,7 +460,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
return RX_HANDLER_CONSUMED;
*pskb = skb;
eth = eth_hdr(skb);
- macvlan_forward_source(skb, port, eth->h_source);
+ if (macvlan_forward_source(skb, port, eth->h_source))
+ return RX_HANDLER_CONSUMED;
src = macvlan_hash_lookup(port, eth->h_source);
if (src && src->mode != MACVLAN_MODE_VEPA &&
src->mode != MACVLAN_MODE_BRIDGE) {
@@ -482,7 +480,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
return RX_HANDLER_PASS;
}
- macvlan_forward_source(skb, port, eth->h_source);
+ if (macvlan_forward_source(skb, port, eth->h_source))
+ return RX_HANDLER_CONSUMED;
if (macvlan_passthru(port))
vlan = list_first_or_null_rcu(&port->vlans,
struct macvlan_dev, list);
@@ -1286,7 +1285,8 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[],
return 0;
if (data[IFLA_MACVLAN_FLAGS] &&
- nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~MACVLAN_FLAG_NOPROMISC)
+ nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~(MACVLAN_FLAG_NOPROMISC |
+ MACVLAN_FLAG_NODST))
return -EINVAL;
if (data[IFLA_MACVLAN_MODE]) {