diff options
author | Alex Williamson <alex.williamson@hp.com> | 2009-02-04 04:02:45 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-02-04 19:35:13 -0500 |
commit | f565a7c259d71cc186753653d978c646d2354b36 (patch) | |
tree | 67eac82cc9043d80e77c2627b3de862da1cca439 /drivers/net/virtio_net.c | |
parent | 2af7698e2dd698d452ab9d63a9ca5956bbe8fc3b (diff) |
virtio_net: Add a MAC filter table
Make use of the MAC control virtqueue class to support a MAC
filter table. The filter table is managed by the hypervisor.
We consider the table to be available if the CTRL_RX feature
bit is set. We leave it to the hypervisor to manage the table
and enable promiscuous or all-multi mode as necessary depending
on the resources available to it.
Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r-- | drivers/net/virtio_net.c | 55 |
1 files changed, 47 insertions, 8 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1abea9dc6f0f..daab9c9b0a40 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -37,7 +37,7 @@ module_param(gso, bool, 0444); | |||
37 | #define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN) | 37 | #define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN) |
38 | #define GOOD_COPY_LEN 128 | 38 | #define GOOD_COPY_LEN 128 |
39 | 39 | ||
40 | #define VIRTNET_SEND_COMMAND_SG_MAX 1 | 40 | #define VIRTNET_SEND_COMMAND_SG_MAX 2 |
41 | 41 | ||
42 | struct virtnet_info | 42 | struct virtnet_info |
43 | { | 43 | { |
@@ -661,31 +661,70 @@ static int virtnet_set_tx_csum(struct net_device *dev, u32 data) | |||
661 | static void virtnet_set_rx_mode(struct net_device *dev) | 661 | static void virtnet_set_rx_mode(struct net_device *dev) |
662 | { | 662 | { |
663 | struct virtnet_info *vi = netdev_priv(dev); | 663 | struct virtnet_info *vi = netdev_priv(dev); |
664 | struct scatterlist sg; | 664 | struct scatterlist sg[2]; |
665 | u8 promisc, allmulti; | 665 | u8 promisc, allmulti; |
666 | struct virtio_net_ctrl_mac *mac_data; | ||
667 | struct dev_addr_list *addr; | ||
668 | void *buf; | ||
669 | int i; | ||
666 | 670 | ||
667 | /* We can't dynamicaly set ndo_set_rx_mode, so return gracefully */ | 671 | /* We can't dynamicaly set ndo_set_rx_mode, so return gracefully */ |
668 | if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX)) | 672 | if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX)) |
669 | return; | 673 | return; |
670 | 674 | ||
671 | promisc = ((dev->flags & IFF_PROMISC) != 0 || dev->uc_count > 0); | 675 | promisc = ((dev->flags & IFF_PROMISC) != 0); |
672 | allmulti = ((dev->flags & IFF_ALLMULTI) != 0 || dev->mc_count > 0); | 676 | allmulti = ((dev->flags & IFF_ALLMULTI) != 0); |
673 | 677 | ||
674 | sg_set_buf(&sg, &promisc, sizeof(promisc)); | 678 | sg_set_buf(sg, &promisc, sizeof(promisc)); |
675 | 679 | ||
676 | if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, | 680 | if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, |
677 | VIRTIO_NET_CTRL_RX_PROMISC, | 681 | VIRTIO_NET_CTRL_RX_PROMISC, |
678 | &sg, 1, 0)) | 682 | sg, 1, 0)) |
679 | dev_warn(&dev->dev, "Failed to %sable promisc mode.\n", | 683 | dev_warn(&dev->dev, "Failed to %sable promisc mode.\n", |
680 | promisc ? "en" : "dis"); | 684 | promisc ? "en" : "dis"); |
681 | 685 | ||
682 | sg_set_buf(&sg, &allmulti, sizeof(allmulti)); | 686 | sg_set_buf(sg, &allmulti, sizeof(allmulti)); |
683 | 687 | ||
684 | if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, | 688 | if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, |
685 | VIRTIO_NET_CTRL_RX_ALLMULTI, | 689 | VIRTIO_NET_CTRL_RX_ALLMULTI, |
686 | &sg, 1, 0)) | 690 | sg, 1, 0)) |
687 | dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n", | 691 | dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n", |
688 | allmulti ? "en" : "dis"); | 692 | allmulti ? "en" : "dis"); |
693 | |||
694 | /* MAC filter - use one buffer for both lists */ | ||
695 | mac_data = buf = kzalloc(((dev->uc_count + dev->mc_count) * ETH_ALEN) + | ||
696 | (2 * sizeof(mac_data->entries)), GFP_ATOMIC); | ||
697 | if (!buf) { | ||
698 | dev_warn(&dev->dev, "No memory for MAC address buffer\n"); | ||
699 | return; | ||
700 | } | ||
701 | |||
702 | /* Store the unicast list and count in the front of the buffer */ | ||
703 | mac_data->entries = dev->uc_count; | ||
704 | addr = dev->uc_list; | ||
705 | for (i = 0; i < dev->uc_count; i++, addr = addr->next) | ||
706 | memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN); | ||
707 | |||
708 | sg_set_buf(&sg[0], mac_data, | ||
709 | sizeof(mac_data->entries) + (dev->uc_count * ETH_ALEN)); | ||
710 | |||
711 | /* multicast list and count fill the end */ | ||
712 | mac_data = (void *)&mac_data->macs[dev->uc_count][0]; | ||
713 | |||
714 | mac_data->entries = dev->mc_count; | ||
715 | addr = dev->mc_list; | ||
716 | for (i = 0; i < dev->mc_count; i++, addr = addr->next) | ||
717 | memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN); | ||
718 | |||
719 | sg_set_buf(&sg[1], mac_data, | ||
720 | sizeof(mac_data->entries) + (dev->mc_count * ETH_ALEN)); | ||
721 | |||
722 | if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC, | ||
723 | VIRTIO_NET_CTRL_MAC_TABLE_SET, | ||
724 | sg, 2, 0)) | ||
725 | dev_warn(&dev->dev, "Failed to set MAC fitler table.\n"); | ||
726 | |||
727 | kfree(buf); | ||
689 | } | 728 | } |
690 | 729 | ||
691 | static struct ethtool_ops virtnet_ethtool_ops = { | 730 | static struct ethtool_ops virtnet_ethtool_ops = { |