diff --git a/datapath/datapath.c b/datapath/datapath.c index 3acf243..9e81179 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -31,7 +31,9 @@ #include #include #include +#include +#include "openflow/nicira-ext.h" #include "openflow/openflow-netlink.h" #include "datapath.h" #include "nx_act_snat.h" @@ -46,7 +48,7 @@ /* Strings to describe the manufacturer, hardware, and software. This data * is queriable through the switch description stats message. */ -static char mfr_desc[DESC_STR_LEN] = "Nicira Networks"; +static char mfr_desc[DESC_STR_LEN] = "Nicira Networks, Inc."; static char hw_desc[DESC_STR_LEN] = "Reference Linux Kernel Module"; static char sw_desc[DESC_STR_LEN] = VERSION; static char serial_num[SERIAL_NUM_LEN] = "None"; @@ -220,37 +222,15 @@ send_openflow_skb(struct sk_buff *skb, const struct sender *sender) : genlmsg_multicast(skb, 0, mc_group.id, GFP_ATOMIC)); } -/* Generates a unique datapath id. It incorporates the datapath index - * and a hardware address, if available. If not, it generates a random - * one. - */ +/* Retrieves the datapath id, which is the MAC address of the "of" device. */ static -uint64_t gen_datapath_id(uint16_t dp_idx) +uint64_t get_datapath_id(struct net_device *dev) { - uint64_t id; + uint64_t id = 0; int i; - struct net_device *dev; - /* The top 16 bits are used to identify the datapath. The lower 48 bits - * use an interface address. */ - id = (uint64_t)dp_idx << 48; - if ((dev = dev_get_by_name(&init_net, "ctl0")) - || (dev = dev_get_by_name(&init_net, "eth0"))) { - for (i=0; idev_addr[i] << (8*(ETH_ALEN-1 - i)); - } - dev_put(dev); - } else { - /* Randomly choose the lower 48 bits if we cannot find an - * address and mark the most significant bit to indicate that - * this was randomly generated. */ - uint8_t rand[ETH_ALEN]; - get_random_bytes(rand, ETH_ALEN); - id |= (uint64_t)1 << 63; - for (i=0; idev_addr[i] << (8*(ETH_ALEN-1 - i)); return id; } @@ -285,7 +265,7 @@ static int new_dp(int dp_idx) goto err_free_dp; dp->dp_idx = dp_idx; - dp->id = gen_datapath_id(dp_idx); + dp->id = get_datapath_id(dp->netdev); dp->chain = chain_create(dp); if (dp->chain == NULL) goto err_destroy_dp_dev; @@ -1803,6 +1783,33 @@ static void dp_uninit_netlink(void) genl_unregister_family(&dp_genl_family); } +/* Set the description strings if appropriate values are available from + * the DMI. */ +static void set_desc(void) +{ + const char *uuid = dmi_get_system_info(DMI_PRODUCT_UUID); + const char *uptr = uuid + 24; + + 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; + + /* Only set if the UUID is from Nicira. */ + if (strncmp(uptr, NICIRA_OUI_STR, strlen(NICIRA_OUI_STR))) + return; + + strlcpy(mfr_desc, dmi_get_system_info(DMI_SYS_VENDOR), sizeof(mfr_desc)); + snprintf(hw_desc, sizeof(hw_desc), "%s %s", + dmi_get_system_info(DMI_PRODUCT_NAME), + dmi_get_system_info(DMI_PRODUCT_VERSION)); + strlcpy(serial_num, dmi_get_system_info(DMI_PRODUCT_SERIAL), + sizeof(serial_num)); +} + static int __init dp_init(void) { int err; @@ -1822,6 +1829,10 @@ static int __init dp_init(void) if (err) goto error_unreg_notifier; + /* Check if better descriptions of the switch are available than the + * defaults. */ + set_desc(); + /* Hook into callback used by the bridge to intercept packets. * Parasites we are. */ if (br_handle_frame_hook) diff --git a/datapath/dp_dev.c b/datapath/dp_dev.c index 195accb..ee66638 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" @@ -107,6 +108,44 @@ 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 = uuid + 24; + 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. */ + for (i=0; idev_addr, mac, ETH_ALEN); +} + static void do_setup(struct net_device *netdev) { @@ -122,9 +161,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 +190,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); diff --git a/datapath/linux-2.4/compat-2.4/include/linux/dmi.h b/datapath/linux-2.4/compat-2.4/include/linux/dmi.h new file mode 100644 index 0000000..bf51e25 --- /dev/null +++ b/datapath/linux-2.4/compat-2.4/include/linux/dmi.h @@ -0,0 +1,34 @@ +#ifndef __LINUX_DMI_H +#define __LINUX_DMI_H 1 + +enum dmi_field { + DMI_NONE, + DMI_BIOS_VENDOR, + DMI_BIOS_VERSION, + DMI_BIOS_DATE, + DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, + DMI_PRODUCT_VERSION, + DMI_PRODUCT_SERIAL, + DMI_PRODUCT_UUID, + DMI_BOARD_VENDOR, + DMI_BOARD_NAME, + DMI_BOARD_VERSION, + DMI_BOARD_SERIAL, + DMI_BOARD_ASSET_TAG, + DMI_CHASSIS_VENDOR, + DMI_CHASSIS_TYPE, + DMI_CHASSIS_VERSION, + DMI_CHASSIS_SERIAL, + DMI_CHASSIS_ASSET_TAG, + DMI_STRING_MAX +}; + +/* 2.4 kernels didn't provide a general ability to query DMI. We'll just + * always return NULL, since this functionality isn't critical. */ +static inline +const char *dmi_get_system_info(int field) { + return NULL; +} + +#endif diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 821ad6f..da71be3 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -8,6 +8,8 @@ #include "openflow/openflow.h" +#define NICIRA_OUI_STR "002320" + /* The following vendor extensions, proposed by Nicira Networks, are not yet * ready for standardization (and may never be), so they are not included in * openflow.h. */