diff options
Diffstat (limited to 'usr/src/lib/libipmi/common')
-rw-r--r-- | usr/src/lib/libipmi/common/ipmi_lancfg.c | 245 | ||||
-rw-r--r-- | usr/src/lib/libipmi/common/libipmi.h | 12 |
2 files changed, 245 insertions, 12 deletions
diff --git a/usr/src/lib/libipmi/common/ipmi_lancfg.c b/usr/src/lib/libipmi/common/ipmi_lancfg.c index 3e3ebc6e81..b324891e3f 100644 --- a/usr/src/lib/libipmi/common/ipmi_lancfg.c +++ b/usr/src/lib/libipmi/common/ipmi_lancfg.c @@ -22,6 +22,9 @@ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2018, Joyent, Inc. + */ /* * Query and configure LAN interfaces over IPMI. This is done through the @@ -34,6 +37,7 @@ #include <strings.h> #include <libipmi.h> +#include <netinet/in.h> #include "ipmi_impl.h" @@ -65,10 +69,26 @@ typedef struct ipmi_cmd_lan_set_config { #define IPMI_LAN_PARAM_SUBNET_MASK 6 #define IPMI_LAN_PARAM_GATEWAY_ADDR 12 +/* VLAN/IPv6 parameters are currently only supported for GET operations */ +#define IPMI_LAN_PARAM_VLAN_ID 20 +#define IPMI_LAN_PARAM_IPVX_ENABLED 51 +#define IPMI_LAN_PARAM_IPV6_NUM_ADDRS 55 +#define IPMI_LAN_PARAM_IPV6_SADDR 56 +#define IPMI_LAN_PARAM_IPV6_DADDR 59 +#define IPMI_LAN_PARAM_IPV6_ROUTER_CONFIG 64 +#define IPMI_LAN_PARAM_IPV6_STATIC_ROUTE1 65 +#define IPMI_LAN_PARAM_IPV6_STATIC_ROUTE2 68 +#define IPMI_LAN_PARAM_IPV6_NUM_DYN_ROUTES 72 +#define IPMI_LAN_PARAM_IPV6_DYN_ROUTE 73 + #define IPMI_LAN_SET_COMPLETE 0x0 #define IPMI_LAN_SET_INPROGRESS 0x1 #define IPMI_LAN_SET_COMMIT 0x2 +/* bitfield values of IPMI_LAN_PARAM_IPV6_ROUTER_CONFIG param */ +#define IPMI_LAN_IPV6_STATIC_ROUTES_ENABLED 0x1 +#define IPMI_LAN_IPV6_DYNAMIC_ROUTES_ENABLED 0x2 + typedef struct ipmi_lan_entry { int ile_param; int ile_mask; @@ -78,7 +98,7 @@ typedef struct ipmi_lan_entry { size_t ile_len; } ipmi_lan_entry_t; -static ipmi_lan_entry_t ipmi_lan_table[] = { +static ipmi_lan_entry_t ipmi_lan_ipv4_table[] = { { IPMI_LAN_PARAM_IP_ADDR, IPMI_LAN_SET_IPADDR, 0, 0, offsetof(ipmi_lan_config_t, ilc_ipaddr), sizeof (uint32_t) }, { IPMI_LAN_PARAM_IP_SOURCE, IPMI_LAN_SET_IPADDR_SOURCE, 0, 0, @@ -91,8 +111,8 @@ static ipmi_lan_entry_t ipmi_lan_table[] = { offsetof(ipmi_lan_config_t, ilc_gateway_addr), sizeof (uint32_t) } }; -#define IPMI_LAN_NENTRIES \ - (sizeof (ipmi_lan_table) / sizeof (ipmi_lan_table[0])) +#define IPMI_LAN_IPV4_NENTRIES \ + (sizeof (ipmi_lan_ipv4_table) / sizeof (ipmi_lan_ipv4_table[0])) static int ipmi_lan_get_param(ipmi_handle_t *ihp, int channel, int param, int set, @@ -129,15 +149,44 @@ ipmi_lan_get_param(ipmi_handle_t *ihp, int channel, int param, int set, return (0); } +struct ipmi_lan_ipv6_addr { + uint8_t ipva_selector; + uint8_t ipva_source; + uint8_t ipva_addr[16]; + uint8_t ipva_prefixlen; + uint8_t ipva_status; +}; + +struct ipmi_lan_ipv6_numaddrs { + uint8_t inva_num_saddrs; + uint8_t inva_num_daddrs; + uint8_t inva_support; +}; + +struct ipmi_lan_vlan_cfg { + uint8_t ivla_vlanid_lower; + DECL_BITFIELD3( + ivla_vlanid_upper :4, + __reserved :3, + ivla_vlan_enable :1); +}; + int ipmi_lan_get_config(ipmi_handle_t *ihp, int channel, ipmi_lan_config_t *cfgp) { - uint8_t set; - int i; + uint8_t set, enabled, route_cfg, ndynroutes = 0; + int i, j; ipmi_lan_entry_t *lep; + struct ipmi_lan_ipv6_numaddrs numaddrs = { 0 }; + struct ipmi_lan_ipv6_addr addrv6 = { 0 }; + struct ipmi_lan_vlan_cfg vlancfg = { 0 }; + struct in6_addr sroute1 = { 0 }, sroute2 = { 0 }, droute = { 0 }; + boolean_t found_addr = B_FALSE; + boolean_t stat_routes_enabled = B_FALSE, dyn_routes_enabled = B_FALSE; if (ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_SET_IN_PROGRESS, 0, 0, &set, sizeof (set)) != 0) + /* errno set */ return (-1); if (set & IPMI_LAN_SET_INPROGRESS) @@ -145,14 +194,186 @@ ipmi_lan_get_config(ipmi_handle_t *ihp, int channel, ipmi_lan_config_t *cfgp) else cfgp->ilc_set_in_progress = B_FALSE; - for (i = 0; i < IPMI_LAN_NENTRIES; i++) { - lep = &ipmi_lan_table[i]; - if (ipmi_lan_get_param(ihp, channel, lep->ile_param, - lep->ile_set, lep->ile_block, - (char *)cfgp + lep->ile_offset, lep->ile_len) != 0) + /* + * First determine which IP addressing modes (IPv4/6) are enabled. On + * service processors that don't support a version of IPMI that is + * IPv6-aware, this parameter won't exist. If we fail to look it up + * then we'll assume that only IPv4 is enabled. + */ + if (ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_IPVX_ENABLED, 0, 0, + &enabled, sizeof (enabled)) != 0) { + cfgp->ilc_ipv4_enabled = B_TRUE; + cfgp->ilc_ipv6_enabled = B_FALSE; + } else { + switch (enabled) { + case 0: + cfgp->ilc_ipv4_enabled = B_TRUE; + cfgp->ilc_ipv6_enabled = B_FALSE; + break; + case 1: + cfgp->ilc_ipv4_enabled = B_FALSE; + cfgp->ilc_ipv6_enabled = B_TRUE; + break; + case 2: + cfgp->ilc_ipv4_enabled = B_TRUE; + cfgp->ilc_ipv6_enabled = B_TRUE; + break; + default: + return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE, NULL)); + } + } + + /* If IPv4 support is enabled, gather the current configuration. */ + if (cfgp->ilc_ipv4_enabled == B_TRUE) { + for (i = 0; i < IPMI_LAN_IPV4_NENTRIES; i++) { + lep = &ipmi_lan_ipv4_table[i]; + if (ipmi_lan_get_param(ihp, channel, lep->ile_param, + lep->ile_set, lep->ile_block, + (char *)cfgp + lep->ile_offset, lep->ile_len) != 0) + /* errno set */ + return (-1); + } + } + + /* Next check if VLAN is enabled, and if so, grab the VLAN ID. */ + if (ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_VLAN_ID, 0, + 0, &vlancfg, sizeof (struct ipmi_lan_vlan_cfg)) != 0) { + /* errno set */ + return (-1); + } + cfgp->ilc_vlan_enabled = vlancfg.ivla_vlan_enable; + if (cfgp->ilc_vlan_enabled == B_TRUE) { + cfgp->ilc_vlan_id = (vlancfg.ivla_vlanid_upper << 8) | + vlancfg.ivla_vlanid_lower; + } + + /* If IPv6 support isn't enabled, then we're all done here. */ + if (cfgp->ilc_ipv6_enabled != B_TRUE) + return (0); + + /* + * First check for a static address. If we can't find one, we'll look + * for a dynamic address. The spec allows for multiple IPv6 static and + * dynamic addresses to exist in various states. For simplicity, we + * will search for the first address that is configured and active. + */ + if (ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_IPV6_NUM_ADDRS, 0, + 0, &numaddrs, sizeof (numaddrs)) != 0) { + /* errno set */ + return (-1); + } + + for (i = 0; i < numaddrs.inva_num_saddrs; i++) { + if (ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_IPV6_SADDR, + i, 0, &addrv6, sizeof (addrv6)) == 0 && + addrv6.ipva_status == 0) { + found_addr = B_TRUE; + cfgp->ilc_ipv6_source = IPMI_LAN_SRC_STATIC; + break; + } + } + for (i = 0; found_addr == B_FALSE && i < numaddrs.inva_num_daddrs; + i++) { + if (ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_IPV6_DADDR, + i, 0, &addrv6, sizeof (addrv6)) == 0 && + addrv6.ipva_status == 0) { + found_addr = B_TRUE; + cfgp->ilc_ipv6_source = IPMI_LAN_SRC_DHCP; + break; + } + } + + /* + * If we didn't find any active static or dynamic addresses, then + * while IPv6 support is enabled, no IPv6 interfaces have been + * configured. We reset ilc_ipv6_enabled back to false so that + * callers know that the other ilc_ipv6_* fields are not valid. + */ + if (found_addr != B_TRUE) { + cfgp->ilc_ipv6_enabled = B_FALSE; + return (0); + } + + (void) memcpy(cfgp->ilc_ipv6_addr, addrv6.ipva_addr, + sizeof (addrv6.ipva_addr)); + + /* + * For the case that static addressing was used for the SP IP then we + * need to get the IPMI_LAN_PARAM_IPV6_ROUTER_CONFIG parameter to + * determine if static or dynamic routes are enabled (or both). + * + * If DHCP was used to assign the SP IP, then only dynamic route + * discovery is supported. + */ + if (cfgp->ilc_ipv6_source == IPMI_LAN_SRC_STATIC && + ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_IPV6_ROUTER_CONFIG, + 0, 0, &route_cfg, sizeof (route_cfg)) != 0) { + /* errno set */ + return (-1); + } + + if (cfgp->ilc_ipv6_source == IPMI_LAN_SRC_STATIC) { + if (route_cfg & IPMI_LAN_IPV6_STATIC_ROUTES_ENABLED) + stat_routes_enabled = B_TRUE; + if (route_cfg & IPMI_LAN_IPV6_DYNAMIC_ROUTES_ENABLED) + dyn_routes_enabled = B_TRUE; + } else { + dyn_routes_enabled = B_TRUE; + } + + /* + * The IPMI spec allows for a max of two static IPv6 routes to be + * configured. + */ + j = cfgp->ilc_ipv6_nroutes = 0; + if (stat_routes_enabled == B_TRUE) { + cfgp->ilc_ipv6_nroutes = 2; + if (ipmi_lan_get_param(ihp, channel, + IPMI_LAN_PARAM_IPV6_STATIC_ROUTE1, 0, 0, &sroute1, + sizeof (sroute1)) != 0 || + ipmi_lan_get_param(ihp, channel, + IPMI_LAN_PARAM_IPV6_STATIC_ROUTE2, 0, 0, &sroute1, + sizeof (sroute2)) != 0) { + /* errno set */ return (-1); + } + if (IN6_IS_ADDR_UNSPECIFIED(&sroute1)) { + cfgp->ilc_ipv6_nroutes++; + (void) memcpy(cfgp->ilc_ipv6_routes[j++], &sroute1, + sizeof (sroute1)); + } + if (IN6_IS_ADDR_UNSPECIFIED(&sroute2) != B_TRUE) { + cfgp->ilc_ipv6_nroutes++; + (void) memcpy(cfgp->ilc_ipv6_routes[j++], &sroute2, + sizeof (sroute2)); + } } + /* + * RFC4861 states that if dynamic routing is used, a host should retain + * a minimum of two routes, though more is recommended. Retrieve the + * number of dynamic routes and then iterate through them and gather + * up to the first two addresses. + */ + if (dyn_routes_enabled == B_TRUE && + ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_IPV6_NUM_DYN_ROUTES, + 0, 0, &ndynroutes, sizeof (ndynroutes)) != 0) { + /* errno set */ + return (-1); + } + for (i = 0; i < ndynroutes && i < 2; i++) { + if (ipmi_lan_get_param(ihp, channel, + IPMI_LAN_PARAM_IPV6_DYN_ROUTE, i, 0, &droute, + sizeof (droute)) != 0) + /* errno set */ + return (-1); + + if (IN6_IS_ADDR_UNSPECIFIED(&droute) != B_TRUE) { + (void) memcpy(cfgp->ilc_ipv6_routes[j++], &droute, + sizeof (droute)); + cfgp->ilc_ipv6_nroutes++; + } + } return (0); } @@ -220,8 +441,8 @@ ipmi_lan_set_config(ipmi_handle_t *ihp, int channel, ipmi_lan_config_t *cfgp, /* * Iterate over all parameters and set them. */ - for (i = 0; i < IPMI_LAN_NENTRIES; i++) { - lep = &ipmi_lan_table[i]; + for (i = 0; i < IPMI_LAN_IPV4_NENTRIES; i++) { + lep = &ipmi_lan_ipv4_table[i]; if (!(lep->ile_mask & mask)) continue; diff --git a/usr/src/lib/libipmi/common/libipmi.h b/usr/src/lib/libipmi/common/libipmi.h index 1e69e57854..c3605616ed 100644 --- a/usr/src/lib/libipmi/common/libipmi.h +++ b/usr/src/lib/libipmi/common/libipmi.h @@ -297,6 +297,9 @@ extern ipmi_channel_info_t *ipmi_get_channel_info(ipmi_handle_t *, int); * This can be expanded in the future as needed. */ +/* We'll return up to a maximum of two static routee + two dynamic routes */ +#define IPMI_LAN_IPV6_MAX_ROUTES 4 + typedef struct ipmi_lan_config { boolean_t ilc_set_in_progress; uint32_t ilc_ipaddr; @@ -304,8 +307,17 @@ typedef struct ipmi_lan_config { uint8_t ilc_macaddr[6]; uint32_t ilc_subnet; uint32_t ilc_gateway_addr; + uint8_t ilc_ipv6_source; + uint8_t ilc_ipv6_addr[16]; + uint8_t ilc_ipv6_routes[IPMI_LAN_IPV6_MAX_ROUTES][16]; + uint8_t ilc_ipv6_nroutes; + uint16_t ilc_vlan_id; + boolean_t ilc_ipv4_enabled; + boolean_t ilc_ipv6_enabled; + boolean_t ilc_vlan_enabled; } ipmi_lan_config_t; +/* values for ilc_ipaddr_source */ #define IPMI_LAN_SRC_UNSPECIFIED 0x0 #define IPMI_LAN_SRC_STATIC 0x1 #define IPMI_LAN_SRC_DHCP 0x2 |