diff options
author | David S. Miller <davem@davemloft.net> | 2013-01-21 14:14:09 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-21 14:14:09 -0500 |
commit | cd5f20461de8e3e9b04932e4ba3e37afe39b8898 (patch) | |
tree | 26b31fbcf0995c22b073394946717eba0151fbe5 | |
parent | 3fcd550a4b37b1c60b4afce2e4b200919ec8bd20 (diff) | |
parent | 7e58d5aea8abb993983a3f3088fd4a3f06180a1c (diff) |
Merge branch 'virtio_mac'
Amos Kong says:
====================
Currenly mac is programmed byte by byte. This means that we
have an intermediate step where mac is wrong.
Third patch introduced a new vq control command to set mac
address, it's atomic.
V2: check return of sending command, delay eth_mac_addr()
V3: restore software address when fail to set hardware address
V4: split eth_mac_addr, fix error handle
V5: rebase patches to net-next tree
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/virtio_net.c | 110 | ||||
-rw-r--r-- | include/linux/etherdevice.h | 2 | ||||
-rw-r--r-- | include/uapi/linux/virtio_net.h | 8 | ||||
-rw-r--r-- | net/ethernet/eth.c | 41 |
4 files changed, 106 insertions, 55 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a6fcf15adc4f..701408a1ded6 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -753,19 +753,77 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
753 | return NETDEV_TX_OK; | 753 | return NETDEV_TX_OK; |
754 | } | 754 | } |
755 | 755 | ||
756 | /* | ||
757 | * Send command via the control virtqueue and check status. Commands | ||
758 | * supported by the hypervisor, as indicated by feature bits, should | ||
759 | * never fail unless improperly formated. | ||
760 | */ | ||
761 | static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, | ||
762 | struct scatterlist *data, int out, int in) | ||
763 | { | ||
764 | struct scatterlist *s, sg[VIRTNET_SEND_COMMAND_SG_MAX + 2]; | ||
765 | struct virtio_net_ctrl_hdr ctrl; | ||
766 | virtio_net_ctrl_ack status = ~0; | ||
767 | unsigned int tmp; | ||
768 | int i; | ||
769 | |||
770 | /* Caller should know better */ | ||
771 | BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) || | ||
772 | (out + in > VIRTNET_SEND_COMMAND_SG_MAX)); | ||
773 | |||
774 | out++; /* Add header */ | ||
775 | in++; /* Add return status */ | ||
776 | |||
777 | ctrl.class = class; | ||
778 | ctrl.cmd = cmd; | ||
779 | |||
780 | sg_init_table(sg, out + in); | ||
781 | |||
782 | sg_set_buf(&sg[0], &ctrl, sizeof(ctrl)); | ||
783 | for_each_sg(data, s, out + in - 2, i) | ||
784 | sg_set_buf(&sg[i + 1], sg_virt(s), s->length); | ||
785 | sg_set_buf(&sg[out + in - 1], &status, sizeof(status)); | ||
786 | |||
787 | BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0); | ||
788 | |||
789 | virtqueue_kick(vi->cvq); | ||
790 | |||
791 | /* Spin for a response, the kick causes an ioport write, trapping | ||
792 | * into the hypervisor, so the request should be handled immediately. | ||
793 | */ | ||
794 | while (!virtqueue_get_buf(vi->cvq, &tmp)) | ||
795 | cpu_relax(); | ||
796 | |||
797 | return status == VIRTIO_NET_OK; | ||
798 | } | ||
799 | |||
756 | static int virtnet_set_mac_address(struct net_device *dev, void *p) | 800 | static int virtnet_set_mac_address(struct net_device *dev, void *p) |
757 | { | 801 | { |
758 | struct virtnet_info *vi = netdev_priv(dev); | 802 | struct virtnet_info *vi = netdev_priv(dev); |
759 | struct virtio_device *vdev = vi->vdev; | 803 | struct virtio_device *vdev = vi->vdev; |
760 | int ret; | 804 | int ret; |
805 | struct sockaddr *addr = p; | ||
806 | struct scatterlist sg; | ||
761 | 807 | ||
762 | ret = eth_mac_addr(dev, p); | 808 | ret = eth_prepare_mac_addr_change(dev, p); |
763 | if (ret) | 809 | if (ret) |
764 | return ret; | 810 | return ret; |
765 | 811 | ||
766 | if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) | 812 | if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) { |
813 | sg_init_one(&sg, addr->sa_data, dev->addr_len); | ||
814 | if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC, | ||
815 | VIRTIO_NET_CTRL_MAC_ADDR_SET, | ||
816 | &sg, 1, 0)) { | ||
817 | dev_warn(&vdev->dev, | ||
818 | "Failed to set mac address by vq command.\n"); | ||
819 | return -EINVAL; | ||
820 | } | ||
821 | } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) { | ||
767 | vdev->config->set(vdev, offsetof(struct virtio_net_config, mac), | 822 | vdev->config->set(vdev, offsetof(struct virtio_net_config, mac), |
768 | dev->dev_addr, dev->addr_len); | 823 | addr->sa_data, dev->addr_len); |
824 | } | ||
825 | |||
826 | eth_commit_mac_addr_change(dev, p); | ||
769 | 827 | ||
770 | return 0; | 828 | return 0; |
771 | } | 829 | } |
@@ -819,51 +877,6 @@ static void virtnet_netpoll(struct net_device *dev) | |||
819 | } | 877 | } |
820 | #endif | 878 | #endif |
821 | 879 | ||
822 | /* | ||
823 | * Send command via the control virtqueue and check status. Commands | ||
824 | * supported by the hypervisor, as indicated by feature bits, should | ||
825 | * never fail unless improperly formated. | ||
826 | */ | ||
827 | static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, | ||
828 | struct scatterlist *data, int out, int in) | ||
829 | { | ||
830 | struct scatterlist *s, sg[VIRTNET_SEND_COMMAND_SG_MAX + 2]; | ||
831 | struct virtio_net_ctrl_hdr ctrl; | ||
832 | virtio_net_ctrl_ack status = ~0; | ||
833 | unsigned int tmp; | ||
834 | int i; | ||
835 | |||
836 | /* Caller should know better */ | ||
837 | BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) || | ||
838 | (out + in > VIRTNET_SEND_COMMAND_SG_MAX)); | ||
839 | |||
840 | out++; /* Add header */ | ||
841 | in++; /* Add return status */ | ||
842 | |||
843 | ctrl.class = class; | ||
844 | ctrl.cmd = cmd; | ||
845 | |||
846 | sg_init_table(sg, out + in); | ||
847 | |||
848 | sg_set_buf(&sg[0], &ctrl, sizeof(ctrl)); | ||
849 | for_each_sg(data, s, out + in - 2, i) | ||
850 | sg_set_buf(&sg[i + 1], sg_virt(s), s->length); | ||
851 | sg_set_buf(&sg[out + in - 1], &status, sizeof(status)); | ||
852 | |||
853 | BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0); | ||
854 | |||
855 | virtqueue_kick(vi->cvq); | ||
856 | |||
857 | /* | ||
858 | * Spin for a response, the kick causes an ioport write, trapping | ||
859 | * into the hypervisor, so the request should be handled immediately. | ||
860 | */ | ||
861 | while (!virtqueue_get_buf(vi->cvq, &tmp)) | ||
862 | cpu_relax(); | ||
863 | |||
864 | return status == VIRTIO_NET_OK; | ||
865 | } | ||
866 | |||
867 | static void virtnet_ack_link_announce(struct virtnet_info *vi) | 880 | static void virtnet_ack_link_announce(struct virtnet_info *vi) |
868 | { | 881 | { |
869 | rtnl_lock(); | 882 | rtnl_lock(); |
@@ -1628,6 +1641,7 @@ static unsigned int features[] = { | |||
1628 | VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, | 1641 | VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, |
1629 | VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, | 1642 | VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, |
1630 | VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, | 1643 | VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, |
1644 | VIRTIO_NET_F_CTRL_MAC_ADDR, | ||
1631 | }; | 1645 | }; |
1632 | 1646 | ||
1633 | static struct virtio_driver virtio_net_driver = { | 1647 | static struct virtio_driver virtio_net_driver = { |
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 1a43e1b4f7ad..c623861964e4 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h | |||
@@ -40,6 +40,8 @@ extern int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh, | |||
40 | extern void eth_header_cache_update(struct hh_cache *hh, | 40 | extern void eth_header_cache_update(struct hh_cache *hh, |
41 | const struct net_device *dev, | 41 | const struct net_device *dev, |
42 | const unsigned char *haddr); | 42 | const unsigned char *haddr); |
43 | extern int eth_prepare_mac_addr_change(struct net_device *dev, void *p); | ||
44 | extern void eth_commit_mac_addr_change(struct net_device *dev, void *p); | ||
43 | extern int eth_mac_addr(struct net_device *dev, void *p); | 45 | extern int eth_mac_addr(struct net_device *dev, void *p); |
44 | extern int eth_change_mtu(struct net_device *dev, int new_mtu); | 46 | extern int eth_change_mtu(struct net_device *dev, int new_mtu); |
45 | extern int eth_validate_addr(struct net_device *dev); | 47 | extern int eth_validate_addr(struct net_device *dev); |
diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h index 848e3584d7c8..a5a8c88753b9 100644 --- a/include/uapi/linux/virtio_net.h +++ b/include/uapi/linux/virtio_net.h | |||
@@ -53,6 +53,7 @@ | |||
53 | * network */ | 53 | * network */ |
54 | #define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow | 54 | #define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow |
55 | * Steering */ | 55 | * Steering */ |
56 | #define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */ | ||
56 | 57 | ||
57 | #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ | 58 | #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ |
58 | #define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */ | 59 | #define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */ |
@@ -127,7 +128,7 @@ typedef __u8 virtio_net_ctrl_ack; | |||
127 | #define VIRTIO_NET_CTRL_RX_NOBCAST 5 | 128 | #define VIRTIO_NET_CTRL_RX_NOBCAST 5 |
128 | 129 | ||
129 | /* | 130 | /* |
130 | * Control the MAC filter table. | 131 | * Control the MAC |
131 | * | 132 | * |
132 | * The MAC filter table is managed by the hypervisor, the guest should | 133 | * The MAC filter table is managed by the hypervisor, the guest should |
133 | * assume the size is infinite. Filtering should be considered | 134 | * assume the size is infinite. Filtering should be considered |
@@ -140,6 +141,10 @@ typedef __u8 virtio_net_ctrl_ack; | |||
140 | * first sg list contains unicast addresses, the second is for multicast. | 141 | * first sg list contains unicast addresses, the second is for multicast. |
141 | * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature | 142 | * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature |
142 | * is available. | 143 | * is available. |
144 | * | ||
145 | * The ADDR_SET command requests one out scatterlist, it contains a | ||
146 | * 6 bytes MAC address. This functionality is present if the | ||
147 | * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available. | ||
143 | */ | 148 | */ |
144 | struct virtio_net_ctrl_mac { | 149 | struct virtio_net_ctrl_mac { |
145 | __u32 entries; | 150 | __u32 entries; |
@@ -148,6 +153,7 @@ struct virtio_net_ctrl_mac { | |||
148 | 153 | ||
149 | #define VIRTIO_NET_CTRL_MAC 1 | 154 | #define VIRTIO_NET_CTRL_MAC 1 |
150 | #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 | 155 | #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 |
156 | #define VIRTIO_NET_CTRL_MAC_ADDR_SET 1 | ||
151 | 157 | ||
152 | /* | 158 | /* |
153 | * Control VLAN filtering | 159 | * Control VLAN filtering |
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index bc39c8c8f589..a36c85eab5b4 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c | |||
@@ -272,6 +272,36 @@ void eth_header_cache_update(struct hh_cache *hh, | |||
272 | EXPORT_SYMBOL(eth_header_cache_update); | 272 | EXPORT_SYMBOL(eth_header_cache_update); |
273 | 273 | ||
274 | /** | 274 | /** |
275 | * eth_prepare_mac_addr_change - prepare for mac change | ||
276 | * @dev: network device | ||
277 | * @p: socket address | ||
278 | */ | ||
279 | int eth_prepare_mac_addr_change(struct net_device *dev, void *p) | ||
280 | { | ||
281 | struct sockaddr *addr = p; | ||
282 | |||
283 | if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) | ||
284 | return -EBUSY; | ||
285 | if (!is_valid_ether_addr(addr->sa_data)) | ||
286 | return -EADDRNOTAVAIL; | ||
287 | return 0; | ||
288 | } | ||
289 | EXPORT_SYMBOL(eth_prepare_mac_addr_change); | ||
290 | |||
291 | /** | ||
292 | * eth_commit_mac_addr_change - commit mac change | ||
293 | * @dev: network device | ||
294 | * @p: socket address | ||
295 | */ | ||
296 | void eth_commit_mac_addr_change(struct net_device *dev, void *p) | ||
297 | { | ||
298 | struct sockaddr *addr = p; | ||
299 | |||
300 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
301 | } | ||
302 | EXPORT_SYMBOL(eth_commit_mac_addr_change); | ||
303 | |||
304 | /** | ||
275 | * eth_mac_addr - set new Ethernet hardware address | 305 | * eth_mac_addr - set new Ethernet hardware address |
276 | * @dev: network device | 306 | * @dev: network device |
277 | * @p: socket address | 307 | * @p: socket address |
@@ -283,13 +313,12 @@ EXPORT_SYMBOL(eth_header_cache_update); | |||
283 | */ | 313 | */ |
284 | int eth_mac_addr(struct net_device *dev, void *p) | 314 | int eth_mac_addr(struct net_device *dev, void *p) |
285 | { | 315 | { |
286 | struct sockaddr *addr = p; | 316 | int ret; |
287 | 317 | ||
288 | if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) | 318 | ret = eth_prepare_mac_addr_change(dev, p); |
289 | return -EBUSY; | 319 | if (ret < 0) |
290 | if (!is_valid_ether_addr(addr->sa_data)) | 320 | return ret; |
291 | return -EADDRNOTAVAIL; | 321 | eth_commit_mac_addr_change(dev, p); |
292 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
293 | return 0; | 322 | return 0; |
294 | } | 323 | } |
295 | EXPORT_SYMBOL(eth_mac_addr); | 324 | EXPORT_SYMBOL(eth_mac_addr); |