From b7f66c424fb4f58fed7e678d5683851fcbe66e24 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Thu, 30 Oct 2008 16:23:27 -0700 Subject: [PATCH] Pull configuration information from DMI. Pull configuration information from DMI when available. In its current form, it will only use DMI information set by Nicira. Otherwise, it will use default values. This change also makes DPIDs the same as the MAC address of the local OpenFlow device. --- datapath/datapath.c | 71 +++++++++++-------- datapath/dp_dev.c | 49 +++++++++++++ .../linux-2.4/compat-2.4/include/linux/dmi.h | 34 +++++++++ include/openflow/nicira-ext.h | 2 + 4 files changed, 126 insertions(+), 30 deletions(-) create mode 100644 datapath/linux-2.4/compat-2.4/include/linux/dmi.h diff --git a/datapath/datapath.c b/datapath/datapath.c index 3acf24318..9e811797b 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 195accb2a..ee66638b5 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 000000000..bf51e258d --- /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 821ad6f7d..da71be362 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. */ -- 2.43.0