Skip to content

Commit 4417da6

Browse files
kaberDavid S. Miller
authored andcommitted
[NET]: dev: secondary unicast address support
Add support for configuring secondary unicast addresses on network devices. To support this devices capable of filtering multiple unicast addresses need to change their set_multicast_list function to configure unicast filters as well and assign it to dev->set_rx_mode instead of dev->set_multicast_list. Other devices are put into promiscous mode when secondary unicast addresses are present. Signed-off-by: Patrick McHardy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3fba5a8 commit 4417da6

File tree

3 files changed

+139
-54
lines changed

3 files changed

+139
-54
lines changed

include/linux/netdevice.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ struct net_device
397397
unsigned char addr_len; /* hardware address length */
398398
unsigned short dev_id; /* for shared network cards */
399399

400+
struct dev_addr_list *uc_list; /* Secondary unicast mac addresses */
401+
int uc_count; /* Number of installed ucasts */
402+
int uc_promisc;
400403
struct dev_addr_list *mc_list; /* Multicast mac addresses */
401404
int mc_count; /* Number of installed mcasts */
402405
int promiscuity;
@@ -502,6 +505,8 @@ struct net_device
502505
void *saddr,
503506
unsigned len);
504507
int (*rebuild_header)(struct sk_buff *skb);
508+
#define HAVE_SET_RX_MODE
509+
void (*set_rx_mode)(struct net_device *dev);
505510
#define HAVE_MULTICAST
506511
void (*set_multicast_list)(struct net_device *dev);
507512
#define HAVE_SET_MAC_ADDR
@@ -1008,8 +1013,11 @@ extern struct net_device *alloc_netdev(int sizeof_priv, const char *name,
10081013
void (*setup)(struct net_device *));
10091014
extern int register_netdev(struct net_device *dev);
10101015
extern void unregister_netdev(struct net_device *dev);
1011-
/* Functions used for multicast support */
1012-
extern void dev_mc_upload(struct net_device *dev);
1016+
/* Functions used for secondary unicast and multicast support */
1017+
extern void dev_set_rx_mode(struct net_device *dev);
1018+
extern void __dev_set_rx_mode(struct net_device *dev);
1019+
extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen);
1020+
extern int dev_unicast_add(struct net_device *dev, void *addr, int alen);
10131021
extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
10141022
extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
10151023
extern void dev_mc_discard(struct net_device *dev);

net/core/dev.c

Lines changed: 127 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ int dev_open(struct net_device *dev)
942942
/*
943943
* Initialize multicasting status
944944
*/
945-
dev_mc_upload(dev);
945+
dev_set_rx_mode(dev);
946946

947947
/*
948948
* Wakeup transmit queue engine
@@ -2498,17 +2498,7 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
24982498
return 0;
24992499
}
25002500

2501-
/**
2502-
* dev_set_promiscuity - update promiscuity count on a device
2503-
* @dev: device
2504-
* @inc: modifier
2505-
*
2506-
* Add or remove promiscuity from a device. While the count in the device
2507-
* remains above zero the interface remains promiscuous. Once it hits zero
2508-
* the device reverts back to normal filtering operation. A negative inc
2509-
* value is used to drop promiscuity on the device.
2510-
*/
2511-
void dev_set_promiscuity(struct net_device *dev, int inc)
2501+
static void __dev_set_promiscuity(struct net_device *dev, int inc)
25122502
{
25132503
unsigned short old_flags = dev->flags;
25142504

@@ -2517,7 +2507,6 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
25172507
else
25182508
dev->flags |= IFF_PROMISC;
25192509
if (dev->flags != old_flags) {
2520-
dev_mc_upload(dev);
25212510
printk(KERN_INFO "device %s %s promiscuous mode\n",
25222511
dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
25232512
"left");
@@ -2530,6 +2519,25 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
25302519
}
25312520
}
25322521

2522+
/**
2523+
* dev_set_promiscuity - update promiscuity count on a device
2524+
* @dev: device
2525+
* @inc: modifier
2526+
*
2527+
* Add or remove promiscuity from a device. While the count in the device
2528+
* remains above zero the interface remains promiscuous. Once it hits zero
2529+
* the device reverts back to normal filtering operation. A negative inc
2530+
* value is used to drop promiscuity on the device.
2531+
*/
2532+
void dev_set_promiscuity(struct net_device *dev, int inc)
2533+
{
2534+
unsigned short old_flags = dev->flags;
2535+
2536+
__dev_set_promiscuity(dev, inc);
2537+
if (dev->flags != old_flags)
2538+
dev_set_rx_mode(dev);
2539+
}
2540+
25332541
/**
25342542
* dev_set_allmulti - update allmulti count on a device
25352543
* @dev: device
@@ -2550,7 +2558,48 @@ void dev_set_allmulti(struct net_device *dev, int inc)
25502558
if ((dev->allmulti += inc) == 0)
25512559
dev->flags &= ~IFF_ALLMULTI;
25522560
if (dev->flags ^ old_flags)
2553-
dev_mc_upload(dev);
2561+
dev_set_rx_mode(dev);
2562+
}
2563+
2564+
/*
2565+
* Upload unicast and multicast address lists to device and
2566+
* configure RX filtering. When the device doesn't support unicast
2567+
* filtering it is put in promiscous mode while unicast addresses
2568+
* are present.
2569+
*/
2570+
void __dev_set_rx_mode(struct net_device *dev)
2571+
{
2572+
/* dev_open will call this function so the list will stay sane. */
2573+
if (!(dev->flags&IFF_UP))
2574+
return;
2575+
2576+
if (!netif_device_present(dev))
2577+
return;
2578+
2579+
if (dev->set_rx_mode)
2580+
dev->set_rx_mode(dev);
2581+
else {
2582+
/* Unicast addresses changes may only happen under the rtnl,
2583+
* therefore calling __dev_set_promiscuity here is safe.
2584+
*/
2585+
if (dev->uc_count > 0 && !dev->uc_promisc) {
2586+
__dev_set_promiscuity(dev, 1);
2587+
dev->uc_promisc = 1;
2588+
} else if (dev->uc_count == 0 && dev->uc_promisc) {
2589+
__dev_set_promiscuity(dev, -1);
2590+
dev->uc_promisc = 0;
2591+
}
2592+
2593+
if (dev->set_multicast_list)
2594+
dev->set_multicast_list(dev);
2595+
}
2596+
}
2597+
2598+
void dev_set_rx_mode(struct net_device *dev)
2599+
{
2600+
netif_tx_lock_bh(dev);
2601+
__dev_set_rx_mode(dev);
2602+
netif_tx_unlock_bh(dev);
25542603
}
25552604

25562605
int __dev_addr_delete(struct dev_addr_list **list, void *addr, int alen,
@@ -2622,6 +2671,66 @@ void __dev_addr_discard(struct dev_addr_list **list)
26222671
}
26232672
}
26242673

2674+
/**
2675+
* dev_unicast_delete - Release secondary unicast address.
2676+
* @dev: device
2677+
*
2678+
* Release reference to a secondary unicast address and remove it
2679+
* from the device if the reference count drop to zero.
2680+
*
2681+
* The caller must hold the rtnl_mutex.
2682+
*/
2683+
int dev_unicast_delete(struct net_device *dev, void *addr, int alen)
2684+
{
2685+
int err;
2686+
2687+
ASSERT_RTNL();
2688+
2689+
netif_tx_lock_bh(dev);
2690+
err = __dev_addr_delete(&dev->uc_list, addr, alen, 0);
2691+
if (!err) {
2692+
dev->uc_count--;
2693+
__dev_set_rx_mode(dev);
2694+
}
2695+
netif_tx_unlock_bh(dev);
2696+
return err;
2697+
}
2698+
EXPORT_SYMBOL(dev_unicast_delete);
2699+
2700+
/**
2701+
* dev_unicast_add - add a secondary unicast address
2702+
* @dev: device
2703+
*
2704+
* Add a secondary unicast address to the device or increase
2705+
* the reference count if it already exists.
2706+
*
2707+
* The caller must hold the rtnl_mutex.
2708+
*/
2709+
int dev_unicast_add(struct net_device *dev, void *addr, int alen)
2710+
{
2711+
int err;
2712+
2713+
ASSERT_RTNL();
2714+
2715+
netif_tx_lock_bh(dev);
2716+
err = __dev_addr_add(&dev->uc_list, addr, alen, 0);
2717+
if (!err) {
2718+
dev->uc_count++;
2719+
__dev_set_rx_mode(dev);
2720+
}
2721+
netif_tx_unlock_bh(dev);
2722+
return err;
2723+
}
2724+
EXPORT_SYMBOL(dev_unicast_add);
2725+
2726+
static void dev_unicast_discard(struct net_device *dev)
2727+
{
2728+
netif_tx_lock_bh(dev);
2729+
__dev_addr_discard(&dev->uc_list);
2730+
dev->uc_count = 0;
2731+
netif_tx_unlock_bh(dev);
2732+
}
2733+
26252734
unsigned dev_get_flags(const struct net_device *dev)
26262735
{
26272736
unsigned flags;
@@ -2665,7 +2774,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
26652774
* Load in the correct multicast list now the flags have changed.
26662775
*/
26672776

2668-
dev_mc_upload(dev);
2777+
dev_set_rx_mode(dev);
26692778

26702779
/*
26712780
* Have we downed the interface. We handle IFF_UP ourselves
@@ -2678,7 +2787,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
26782787
ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev);
26792788

26802789
if (!ret)
2681-
dev_mc_upload(dev);
2790+
dev_set_rx_mode(dev);
26822791
}
26832792

26842793
if (dev->flags & IFF_UP &&
@@ -3558,8 +3667,9 @@ void unregister_netdevice(struct net_device *dev)
35583667
raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
35593668

35603669
/*
3561-
* Flush the multicast chain
3670+
* Flush the unicast and multicast chains
35623671
*/
3672+
dev_unicast_discard(dev);
35633673
dev_mc_discard(dev);
35643674

35653675
if (dev->uninit)

net/core/dev_mcast.c

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -63,39 +63,6 @@
6363
* We block accesses to device mc filters with netif_tx_lock.
6464
*/
6565

66-
/*
67-
* Update the multicast list into the physical NIC controller.
68-
*/
69-
70-
static void __dev_mc_upload(struct net_device *dev)
71-
{
72-
/* Don't do anything till we up the interface
73-
* [dev_open will call this function so the list will
74-
* stay sane]
75-
*/
76-
77-
if (!(dev->flags&IFF_UP))
78-
return;
79-
80-
/*
81-
* Devices with no set multicast or which have been
82-
* detached don't get set.
83-
*/
84-
85-
if (dev->set_multicast_list == NULL ||
86-
!netif_device_present(dev))
87-
return;
88-
89-
dev->set_multicast_list(dev);
90-
}
91-
92-
void dev_mc_upload(struct net_device *dev)
93-
{
94-
netif_tx_lock_bh(dev);
95-
__dev_mc_upload(dev);
96-
netif_tx_unlock_bh(dev);
97-
}
98-
9966
/*
10067
* Delete a device level multicast
10168
*/
@@ -114,7 +81,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl)
11481
* loaded filter is now wrong. Fix it
11582
*/
11683

117-
__dev_mc_upload(dev);
84+
__dev_set_rx_mode(dev);
11885
}
11986
netif_tx_unlock_bh(dev);
12087
return err;
@@ -132,7 +99,7 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
13299
err = __dev_addr_add(&dev->mc_list, addr, alen, glbl);
133100
if (!err) {
134101
dev->mc_count++;
135-
__dev_mc_upload(dev);
102+
__dev_set_rx_mode(dev);
136103
}
137104
netif_tx_unlock_bh(dev);
138105
return err;

0 commit comments

Comments
 (0)