X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fdp_dev.c;h=ec36361d683f77a595f0a54316d2881ab66c3c1a;hb=refs%2Fheads%2Ffor-nox%2F0.4;hp=195accb2a9cf729a8efcdec86eaa02a1bd36749e;hpb=f593e3ab70ab06acbf97cbb0a9f897dc4f078011;p=sliver-openvswitch.git diff --git a/datapath/dp_dev.c b/datapath/dp_dev.c index 195accb2a..ec36361d6 100644 --- a/datapath/dp_dev.c +++ b/datapath/dp_dev.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "datapath.h" #include "forward.h" @@ -61,6 +62,20 @@ static int dp_dev_xmit(struct sk_buff *skb, struct net_device *netdev) struct dp_dev *dp_dev = dp_dev_priv(netdev); struct datapath *dp = dp_dev->dp; + /* By orphaning 'skb' we will screw up socket accounting slightly, but + * the effect is limited to the device queue length. If we don't + * do this, then the sk_buff will be destructed eventually, but it is + * harder to predict when. */ + skb_orphan(skb); + + /* We are going to modify 'skb', by sticking it on &dp_dev->xmit_queue, + * so we need to have our own clone. (At any rate, fwd_port_input() + * will need its own clone, so there's no benefit to queuing any other + * way.) */ + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return 0; + dp_dev->stats.tx_packets++; dp_dev->stats.tx_bytes += skb->len; @@ -107,6 +122,45 @@ static int dp_dev_stop(struct net_device *netdev) return 0; } +/* Check if the DMI UUID contains a Nicira mac address that should be + * used for this interface. The UUID is assumed to be RFC 4122 + * compliant. */ +static void +set_uuid_mac(struct net_device *netdev) +{ + const char *uuid = dmi_get_system_info(DMI_PRODUCT_UUID); + const char *uptr; + uint8_t mac[ETH_ALEN]; + int i; + + if (!uuid || *uuid == '\0' || strlen(uuid) != 36) + return; + + /* We are only interested version 1 UUIDs, since the last six bytes + * are an IEEE 802 MAC address. */ + if (uuid[14] != '1') + return; + + /* Pull out the embedded MAC address. The kernel's sscanf doesn't + * support field widths on hex digits, so we use this hack. */ + uptr = uuid + 24; + for (i=0; idev_addr, mac, ETH_ALEN); +} + static void do_setup(struct net_device *netdev) { @@ -122,9 +176,14 @@ do_setup(struct net_device *netdev) netdev->flags = IFF_BROADCAST | IFF_MULTICAST; random_ether_addr(netdev->dev_addr); + + /* Set the OUI to the Nicira one. */ netdev->dev_addr[0] = 0x00; netdev->dev_addr[1] = 0x23; netdev->dev_addr[2] = 0x20; + + /* Set the top bits to indicate random Nicira address. */ + netdev->dev_addr[3] |= 0xc0; } @@ -146,6 +205,11 @@ int dp_dev_setup(struct datapath *dp) return err; } + /* For "of0", we check the DMI UUID to see if a Nicira mac address + * is available to use instead of the random one just generated. */ + if (dp->dp_idx == 0) + set_uuid_mac(netdev); + dp_dev = dp_dev_priv(netdev); dp_dev->dp = dp; skb_queue_head_init(&dp_dev->xmit_queue);