promisc is one bit of struct net_device’s flag, which is used to indicate if a device is in promisc status.
1 2 3 4 5 6 7 8 9 10 11 12
30/* Standard interface flags (netdevice->flags). */ 31#define IFF_UP 0x1 /* interface is up */ 32#define IFF_BROADCAST 0x2 /* broadcast address valid */ 33#define IFF_DEBUG 0x4 /* turn on debugging */ 34#define IFF_LOOPBACK 0x8 /* is a loopback net */ 35#define IFF_POINTOPOINT 0x10 /* interface is has p-p link */ 36#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ 37#define IFF_RUNNING 0x40 /* interface RFC2863 OPER_UP */ 38#define IFF_NOARP 0x80 /* no ARP protocol */ 39#define IFF_PROMISC 0x100 /* receive all packets */ 40#define IFF_ALLMULTI 0x200 /* receive all multicast packets*/ ...
There are two kinds of operataion, could cause a NIC enter/leave promisc status.
ip command run mutli on command, just need one off to recover.
1 2
ip linkset dev eth0 promisc on ip linkset dev eth0 promisc off
tcpdump command When tcpdump starts, it let dev to promisc, and just before exit, tcpdump let dev left promisc. All these is done by call kernel api dev_set_promiscuity.
Data struct and function
summary
kernel 3.10 rc6
There is a element promiscuity in struct net device, which is reference for NIC promisc status. Every time we want to set promisc to NIC, the reference increase 1, while unset promisc, the value sub 1.
1
1156unsignedint promiscuity;
When the value change from 0 to 1, or become 0, that netdevice’s ops is called to set/unset promisic status.
call trace
1 2 3 4 5 6 7 8 9 10
> dev_set_promiscuity >> __dev_set_promiscuity >>> dev->promiscuity += inc; >>>> dev->flags |= IFF_PROMISC or &= ~IFF_PROMISC >>> dev_change_rx_flags(dev, IFF_PROMISC); >>>> ops->ndo_change_rx_flags(dev, flags);<== for most nic, the method is null. >> dev_set_rx_mode >>> conststruct net_device_ops *ops = dev->netdev_ops; >>> ops->ndo_set_rx_mode(dev); >>> for e100, e100_set_multicast_list
dev_set_promiscuity
call __dev_set_promiscuity to record the reference of promisc, If real need change status(refer from 0 to 1, or from 1 to 0), call dev_set_rx_mode to really change NIC promisc status.
4490/** 4491 * dev_set_promiscuity - update promiscuity count on a device 4492 * @dev: device 4493 * @inc: modifier 4494 * 4495 * Add or remove promiscuity from a device. While the count in the device 4496 * remains above zero the interface remains promiscuous. Once it hits zero 4497 * the device reverts back to normal filtering operation. A negative inc 4498 * value is used to drop promiscuity on the device. 4499 * Return 0 if successful or a negative errno code on error. 4500 */ 4501intdev_set_promiscuity(struct net_device *dev, int inc) 4502 { 4503unsignedint old_flags = dev->flags; 4504int err; 4505 4506 err = __dev_set_promiscuity(dev, inc); 4507if (err < 0) 4508return err; 4509if (dev->flags != old_flags) 4510 dev_set_rx_mode(dev); 4511return err; 4512 } 4513 EXPORT_SYMBOL(dev_set_promiscuity);
4436staticvoiddev_change_rx_flags(struct net_device *dev, int flags) 4437 { 4438conststructnet_device_ops *ops = dev->netdev_ops; 4439/*Junwei most nic has no this ops ndo_change_rx_flags*/ 4440if ((dev->flags & IFF_UP) && ops->ndo_change_rx_flags) 4441 ops->ndo_change_rx_flags(dev, flags); 4442 }