aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/macvlan.c304
-rw-r--r--include/linux/if_macvlan.h1
-rw-r--r--include/uapi/linux/if_link.h12
3 files changed, 314 insertions, 3 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 726edabff26b..e8a453f1b458 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -35,7 +35,8 @@
35#include <net/xfrm.h> 35#include <net/xfrm.h>
36#include <linux/netpoll.h> 36#include <linux/netpoll.h>
37 37
38#define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE) 38#define MACVLAN_HASH_BITS 8
39#define MACVLAN_HASH_SIZE (1<<MACVLAN_HASH_BITS)
39#define MACVLAN_BC_QUEUE_LEN 1000 40#define MACVLAN_BC_QUEUE_LEN 1000
40 41
41struct macvlan_port { 42struct macvlan_port {
@@ -47,6 +48,14 @@ struct macvlan_port {
47 struct work_struct bc_work; 48 struct work_struct bc_work;
48 bool passthru; 49 bool passthru;
49 int count; 50 int count;
51 struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE];
52};
53
54struct macvlan_source_entry {
55 struct hlist_node hlist;
56 struct macvlan_dev *vlan;
57 unsigned char addr[6+2] __aligned(sizeof(u16));
58 struct rcu_head rcu;
50}; 59};
51 60
52struct macvlan_skb_cb { 61struct macvlan_skb_cb {
@@ -57,6 +66,20 @@ struct macvlan_skb_cb {
57 66
58static void macvlan_port_destroy(struct net_device *dev); 67static void macvlan_port_destroy(struct net_device *dev);
59 68
69/* Hash Ethernet address */
70static u32 macvlan_eth_hash(const unsigned char *addr)
71{
72 u64 value = get_unaligned((u64 *)addr);
73
74 /* only want 6 bytes */
75#ifdef __BIG_ENDIAN
76 value >>= 16;
77#else
78 value <<= 16;
79#endif
80 return hash_64(value, MACVLAN_HASH_BITS);
81}
82
60static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev) 83static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev)
61{ 84{
62 return rcu_dereference(dev->rx_handler_data); 85 return rcu_dereference(dev->rx_handler_data);
@@ -73,20 +96,68 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
73 const unsigned char *addr) 96 const unsigned char *addr)
74{ 97{
75 struct macvlan_dev *vlan; 98 struct macvlan_dev *vlan;
99 u32 idx = macvlan_eth_hash(addr);
76 100
77 hlist_for_each_entry_rcu(vlan, &port->vlan_hash[addr[5]], hlist) { 101 hlist_for_each_entry_rcu(vlan, &port->vlan_hash[idx], hlist) {
78 if (ether_addr_equal_64bits(vlan->dev->dev_addr, addr)) 102 if (ether_addr_equal_64bits(vlan->dev->dev_addr, addr))
79 return vlan; 103 return vlan;
80 } 104 }
81 return NULL; 105 return NULL;
82} 106}
83 107
108static struct macvlan_source_entry *macvlan_hash_lookup_source(
109 const struct macvlan_dev *vlan,
110 const unsigned char *addr)
111{
112 struct macvlan_source_entry *entry;
113 u32 idx = macvlan_eth_hash(addr);
114 struct hlist_head *h = &vlan->port->vlan_source_hash[idx];
115
116 hlist_for_each_entry_rcu(entry, h, hlist) {
117 if (ether_addr_equal_64bits(entry->addr, addr) &&
118 entry->vlan == vlan)
119 return entry;
120 }
121 return NULL;
122}
123
124static int macvlan_hash_add_source(struct macvlan_dev *vlan,
125 const unsigned char *addr)
126{
127 struct macvlan_port *port = vlan->port;
128 struct macvlan_source_entry *entry;
129 struct hlist_head *h;
130
131 entry = macvlan_hash_lookup_source(vlan, addr);
132 if (entry)
133 return 0;
134
135 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
136 if (!entry)
137 return -ENOMEM;
138
139 ether_addr_copy(entry->addr, addr);
140 entry->vlan = vlan;
141 h = &port->vlan_source_hash[macvlan_eth_hash(addr)];
142 hlist_add_head_rcu(&entry->hlist, h);
143 vlan->macaddr_count++;
144
145 return 0;
146}
147
84static void macvlan_hash_add(struct macvlan_dev *vlan) 148static void macvlan_hash_add(struct macvlan_dev *vlan)
85{ 149{
86 struct macvlan_port *port = vlan->port; 150 struct macvlan_port *port = vlan->port;
87 const unsigned char *addr = vlan->dev->dev_addr; 151 const unsigned char *addr = vlan->dev->dev_addr;
152 u32 idx = macvlan_eth_hash(addr);
88 153
89 hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]); 154 hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[idx]);
155}
156
157static void macvlan_hash_del_source(struct macvlan_source_entry *entry)
158{
159 hlist_del_rcu(&entry->hlist);
160 kfree_rcu(entry, rcu);
90} 161}
91 162
92static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync) 163static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync)
@@ -267,6 +338,65 @@ err:
267 atomic_long_inc(&skb->dev->rx_dropped); 338 atomic_long_inc(&skb->dev->rx_dropped);
268} 339}
269 340
341static void macvlan_flush_sources(struct macvlan_port *port,
342 struct macvlan_dev *vlan)
343{
344 int i;
345
346 for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
347 struct hlist_node *h, *n;
348
349 hlist_for_each_safe(h, n, &port->vlan_source_hash[i]) {
350 struct macvlan_source_entry *entry;
351
352 entry = hlist_entry(h, struct macvlan_source_entry,
353 hlist);
354 if (entry->vlan == vlan)
355 macvlan_hash_del_source(entry);
356 }
357 }
358 vlan->macaddr_count = 0;
359}
360
361static void macvlan_forward_source_one(struct sk_buff *skb,
362 struct macvlan_dev *vlan)
363{
364 struct sk_buff *nskb;
365 struct net_device *dev;
366 int len;
367 int ret;
368
369 dev = vlan->dev;
370 if (unlikely(!(dev->flags & IFF_UP)))
371 return;
372
373 nskb = skb_clone(skb, GFP_ATOMIC);
374 if (!nskb)
375 return;
376
377 len = nskb->len + ETH_HLEN;
378 nskb->dev = dev;
379 nskb->pkt_type = PACKET_HOST;
380
381 ret = netif_rx(nskb);
382 macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0);
383}
384
385static void macvlan_forward_source(struct sk_buff *skb,
386 struct macvlan_port *port,
387 const unsigned char *addr)
388{
389 struct macvlan_source_entry *entry;
390 u32 idx = macvlan_eth_hash(addr);
391 struct hlist_head *h = &port->vlan_source_hash[idx];
392
393 hlist_for_each_entry_rcu(entry, h, hlist) {
394 if (ether_addr_equal_64bits(entry->addr, addr))
395 if (entry->vlan->dev->flags & IFF_UP)
396 macvlan_forward_source_one(skb, entry->vlan);
397 }
398}
399
270/* called under rcu_read_lock() from netif_receive_skb */ 400/* called under rcu_read_lock() from netif_receive_skb */
271static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) 401static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
272{ 402{
@@ -285,6 +415,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
285 if (!skb) 415 if (!skb)
286 return RX_HANDLER_CONSUMED; 416 return RX_HANDLER_CONSUMED;