From 84de666edc7f7d835057ae4807a387447c086bcf Mon Sep 17 00:00:00 2001 From: Ryan Zezeski Date: Tue, 21 Jan 2020 12:21:56 -0700 Subject: 11490 SRS ring polling disabled for VLANs 11491 Want DLS bypass for VLAN traffic 11492 add VLVF bypass to ixgbe core 2869 duplicate packets with vnics over aggrs 11489 DLS stat delete and aggr kstat can deadlock Portions contributed by: Theo Schlossnagle Reviewed by: Patrick Mooney Reviewed by: Robert Mustacchi Reviewed by: Dan McDonald Reviewed by: Paul Winder Approved by: Gordon Ross --- usr/src/uts/common/sys/aggr_impl.h | 27 ++++++++++- usr/src/uts/common/sys/mac_client.h | 3 +- usr/src/uts/common/sys/mac_client_impl.h | 83 ++++++++++++++++++++++++++++++-- usr/src/uts/common/sys/mac_client_priv.h | 6 ++- usr/src/uts/common/sys/mac_impl.h | 47 ++++++++++++------ usr/src/uts/common/sys/mac_provider.h | 44 ++++++++++++++--- 6 files changed, 178 insertions(+), 32 deletions(-) (limited to 'usr/src/uts/common/sys') diff --git a/usr/src/uts/common/sys/aggr_impl.h b/usr/src/uts/common/sys/aggr_impl.h index 547c9cc241..415e176ef3 100644 --- a/usr/src/uts/common/sys/aggr_impl.h +++ b/usr/src/uts/common/sys/aggr_impl.h @@ -21,6 +21,8 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2012 OmniTI Computer Consulting, Inc All rights reserved. + * Copyright 2018 Joyent, Inc. */ #ifndef _SYS_AGGR_IMPL_H @@ -54,6 +56,15 @@ extern "C" { */ #define MAC_PSEUDO_RING_INUSE 0x01 +/* + * VLAN filters placed on the Rx pseudo group. + */ +typedef struct aggr_vlan { + list_node_t av_link; + uint16_t av_vid; /* VLAN ID */ + uint_t av_refs; /* num aggr clients using this VID */ +} aggr_vlan_t; + typedef struct aggr_unicst_addr_s { uint8_t aua_addr[ETHERADDRL]; struct aggr_unicst_addr_s *aua_next; @@ -73,6 +84,8 @@ typedef struct aggr_pseudo_rx_group_s { aggr_unicst_addr_t *arg_macaddr; aggr_pseudo_rx_ring_t arg_rings[MAX_RINGS_PER_GROUP]; uint_t arg_ring_cnt; + uint_t arg_untagged; /* num clients untagged */ + list_t arg_vlans; /* VLANs on this group */ } aggr_pseudo_rx_group_t; typedef struct aggr_pseudo_tx_ring_s { @@ -186,11 +199,18 @@ typedef struct aggr_grp_s { uint_t lg_tx_ports_size; /* size of lg_tx_ports */ uint32_t lg_tx_policy; /* outbound policy */ uint8_t lg_mac_tx_policy; - uint64_t lg_ifspeed; link_state_t lg_link_state; + + + /* + * The lg_stat_lock must be held when accessing these fields. + */ + kmutex_t lg_stat_lock; + uint64_t lg_ifspeed; link_duplex_t lg_link_duplex; uint64_t lg_stat[MAC_NSTAT]; uint64_t lg_ether_stat[ETHER_NSTAT]; + aggr_lacp_mode_t lg_lacp_mode; /* off, active, or passive */ Agg_t aggr; /* 802.3ad data */ uint32_t lg_hcksum_txflags; @@ -308,6 +328,8 @@ extern boolean_t aggr_port_notify_link(aggr_grp_t *, aggr_port_t *); extern void aggr_port_init_callbacks(aggr_port_t *); extern void aggr_recv_cb(void *, mac_resource_handle_t, mblk_t *, boolean_t); +extern void aggr_recv_promisc_cb(void *, mac_resource_handle_t, mblk_t *, + boolean_t); extern void aggr_tx_ring_update(void *, uintptr_t); extern void aggr_tx_notify_thread(void *); @@ -338,6 +360,9 @@ extern void aggr_grp_port_wait(aggr_grp_t *); extern int aggr_port_addmac(aggr_port_t *, const uint8_t *); extern void aggr_port_remmac(aggr_port_t *, const uint8_t *); +extern int aggr_port_addvlan(aggr_port_t *, uint16_t); +extern int aggr_port_remvlan(aggr_port_t *, uint16_t); + extern mblk_t *aggr_ring_tx(void *, mblk_t *); extern mblk_t *aggr_find_tx_ring(void *, mblk_t *, uintptr_t, mac_ring_handle_t *); diff --git a/usr/src/uts/common/sys/mac_client.h b/usr/src/uts/common/sys/mac_client.h index 0fc4939503..74f4cbb310 100644 --- a/usr/src/uts/common/sys/mac_client.h +++ b/usr/src/uts/common/sys/mac_client.h @@ -22,7 +22,7 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2013 Joyent, Inc. All rights reserved. + * Copyright 2018 Joyent, Inc. All rights reserved. */ /* @@ -88,6 +88,7 @@ typedef enum { } mac_client_promisc_type_t; /* flags passed to mac_unicast_add() */ + #define MAC_UNICAST_NODUPCHECK 0x0001 #define MAC_UNICAST_PRIMARY 0x0002 #define MAC_UNICAST_HW 0x0004 diff --git a/usr/src/uts/common/sys/mac_client_impl.h b/usr/src/uts/common/sys/mac_client_impl.h index 9b3b4fe369..d5c66684d0 100644 --- a/usr/src/uts/common/sys/mac_client_impl.h +++ b/usr/src/uts/common/sys/mac_client_impl.h @@ -24,7 +24,7 @@ * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ /* - * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright 2018 Joyent, Inc. */ #ifndef _SYS_MAC_CLIENT_IMPL_H @@ -57,7 +57,7 @@ typedef struct mac_unicast_impl_s { /* Protected by */ uint16_t mui_vid; /* SL */ } mac_unicast_impl_t; -#define MAC_CLIENT_FLAGS_PRIMARY 0X0001 +#define MAC_CLIENT_FLAGS_PRIMARY 0x0001 #define MAC_CLIENT_FLAGS_VNIC_PRIMARY 0x0002 #define MAC_CLIENT_FLAGS_MULTI_PRIMARY 0x0004 #define MAC_CLIENT_FLAGS_PASSIVE_PRIMARY 0x0008 @@ -131,12 +131,17 @@ struct mac_client_impl_s { /* Protected by */ uint32_t mci_flags; /* SL */ krwlock_t mci_rw_lock; mac_unicast_impl_t *mci_unicast_list; /* mci_rw_lock */ + /* * The mac_client_impl_t may be shared by multiple clients, i.e * multiple VLANs sharing the same MAC client. In this case the - * address/vid tubles differ and are each associated with their + * address/vid tuples differ and are each associated with their * own flow entry, but the rest underlying components SRS, etc, * are common. + * + * This is only needed to support sun4v vsw. There are several + * places in MAC we could simplify the code if we removed + * sun4v support. */ flow_entry_t *mci_flent_list; /* mci_rw_lock */ uint_t mci_nflents; /* mci_rw_lock */ @@ -224,7 +229,7 @@ extern int mac_tx_percpu_cnt; &(mcip)->mci_flent->fe_resource_props) #define MCIP_EFFECTIVE_PROPS(mcip) \ - (mcip->mci_flent == NULL ? NULL : \ + (mcip->mci_flent == NULL ? NULL : \ &(mcip)->mci_flent->fe_effective_props) #define MCIP_RESOURCE_PROPS_MASK(mcip) \ @@ -313,6 +318,74 @@ extern int mac_tx_percpu_cnt; (((mcip)->mci_state_flags & MCIS_TAG_DISABLE) == 0 && \ (mcip)->mci_nvids == 1) \ +/* + * MAC Client Implementation State (mci_state_flags) + * + * MCIS_IS_VNIC + * + * The client is a VNIC. + * + * MCIS_EXCLUSIVE + * + * The client has exclusive control over the MAC, such that it is + * the sole client of the MAC. + * + * MCIS_TAG_DISABLE + * + * MAC will not add VLAN tags to outgoing traffic. If this flag + * is set it is up to the client to add the correct VLAN tag. + * + * MCIS_STRIP_DISABLE + * + * MAC will not strip the VLAN tags on incoming traffic before + * passing it to mci_rx_fn. This only applies to non-bypass + * traffic. + * + * MCIS_IS_AGGR_PORT + * + * The client represents a port on an aggr. + * + * MCIS_CLIENT_POLL_CAPABLE + * + * The client is capable of polling the Rx TCP/UDP softrings. + * + * MCIS_DESC_LOGGED + * + * This flag is set when the client's link info has been logged + * by the mac_log_linkinfo() timer. This ensures that the + * client's link info is only logged once. + * + * MCIS_SHARE_BOUND + * + * This client has an HIO share bound to it. + * + * MCIS_DISABLE_TX_VID_CHECK + * + * MAC will not check the VID of the client's Tx traffic. + * + * MCIS_USE_DATALINK_NAME + * + * The client is using the same name as its underlying MAC. This + * happens when dlmgmtd is unreachable during client creation. + * + * MCIS_UNICAST_HW + * + * The client requires MAC address hardware classification. This + * is only used by sun4v vsw. + * + * MCIS_IS_AGGR_CLIENT + * + * The client sits atop an aggr. + * + * MCIS_RX_BYPASS_DISABLE + * + * Do not allow the client to enable DLS bypass. + * + * MCIS_NO_UNICAST_ADDR + * + * This client has no MAC unicast addresss associated with it. + * + */ /* MCI state flags */ #define MCIS_IS_VNIC 0x0001 #define MCIS_EXCLUSIVE 0x0002 @@ -325,7 +398,7 @@ extern int mac_tx_percpu_cnt; #define MCIS_DISABLE_TX_VID_CHECK 0x0100 #define MCIS_USE_DATALINK_NAME 0x0200 #define MCIS_UNICAST_HW 0x0400 -#define MCIS_IS_AGGR 0x0800 +#define MCIS_IS_AGGR_CLIENT 0x0800 #define MCIS_RX_BYPASS_DISABLE 0x1000 #define MCIS_NO_UNICAST_ADDR 0x2000 diff --git a/usr/src/uts/common/sys/mac_client_priv.h b/usr/src/uts/common/sys/mac_client_priv.h index 6b409513a6..77475b339e 100644 --- a/usr/src/uts/common/sys/mac_client_priv.h +++ b/usr/src/uts/common/sys/mac_client_priv.h @@ -22,7 +22,7 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2013 Joyent, Inc. All rights reserved. + * Copyright 2018 Joyent, Inc. */ /* @@ -144,6 +144,10 @@ extern void mac_hwring_set_default(mac_handle_t, mac_ring_handle_t); extern int mac_hwgroup_addmac(mac_group_handle_t, const uint8_t *); extern int mac_hwgroup_remmac(mac_group_handle_t, const uint8_t *); +extern int mac_hwgroup_addvlan(mac_group_handle_t, uint16_t); +extern int mac_hwgroup_remvlan(mac_group_handle_t, uint16_t); + +extern boolean_t mac_has_hw_vlan(mac_handle_t); extern void mac_set_upper_mac(mac_client_handle_t, mac_handle_t, mac_resource_props_t *); diff --git a/usr/src/uts/common/sys/mac_impl.h b/usr/src/uts/common/sys/mac_impl.h index 774c4fad9a..eebbde37de 100644 --- a/usr/src/uts/common/sys/mac_impl.h +++ b/usr/src/uts/common/sys/mac_impl.h @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, Joyent, Inc. + * Copyright (c) 2018, Joyent, Inc. */ #ifndef _SYS_MAC_IMPL_H @@ -244,7 +244,7 @@ struct mac_ring_s { (mr)->mr_refcnt++; \ } -#define MR_REFRELE(mr) { \ +#define MR_REFRELE(mr) { \ mutex_enter(&(mr)->mr_lock); \ ASSERT((mr)->mr_refcnt != 0); \ (mr)->mr_refcnt--; \ @@ -255,8 +255,8 @@ struct mac_ring_s { } /* - * Per mac client flow information associated with a RX group. - * The entire structure is SL protected. + * Used to attach MAC clients to an Rx group. The members are SL + * protected. */ typedef struct mac_grp_client { struct mac_grp_client *mgc_next; @@ -270,15 +270,20 @@ typedef struct mac_grp_client { ((g)->mrg_clients->mgc_next == NULL)) ? \ (g)->mrg_clients->mgc_client : NULL) +#define MAC_GROUP_HW_VLAN(g) \ + (((g) != NULL) && \ + ((g)->mrg_info.mgi_addvlan != NULL) && \ + ((g)->mrg_info.mgi_remvlan != NULL)) + /* * Common ring group data structure for ring control and management. - * The entire structure is SL protected + * The entire structure is SL protected. */ struct mac_group_s { int mrg_index; /* index in the list */ mac_ring_type_t mrg_type; /* ring type */ mac_group_state_t mrg_state; /* state of the group */ - mac_group_t *mrg_next; /* next ring in the chain */ + mac_group_t *mrg_next; /* next group in the chain */ mac_handle_t mrg_mh; /* reference to MAC */ mac_ring_t *mrg_rings; /* grouped rings */ uint_t mrg_cur_count; /* actual size of group */ @@ -300,7 +305,7 @@ struct mac_group_s { mac_ring_handle_t mrh = rh; \ mac_impl_t *mimpl = (mac_impl_t *)mhp; \ /* \ - * Send packets through a selected tx ring, or through the \ + * Send packets through a selected tx ring, or through the \ * default handler if there is no selected ring. \ */ \ if (mrh == NULL) \ @@ -322,9 +327,9 @@ struct mac_group_s { #define MAC_TX(mip, rh, mp, src_mcip) { \ mac_ring_handle_t rhandle = (rh); \ /* \ - * If there is a bound Hybrid I/O share, send packets through \ + * If there is a bound Hybrid I/O share, send packets through \ * the default tx ring. (When there's a bound Hybrid I/O share, \ - * the tx rings of this client are mapped in the guest domain \ + * the tx rings of this client are mapped in the guest domain \ * and not accessible from here.) \ */ \ _NOTE(CONSTANTCONDITION) \ @@ -333,7 +338,7 @@ struct mac_group_s { if (mip->mi_promisc_list != NULL) \ mac_promisc_dispatch(mip, mp, src_mcip); \ /* \ - * Grab the proper transmit pointer and handle. Special \ + * Grab the proper transmit pointer and handle. Special \ * optimization: we can test mi_bridge_link itself atomically, \ * and if that indicates no bridge send packets through tx ring.\ */ \ @@ -360,17 +365,23 @@ typedef struct mac_mcast_addrs_s { } mac_mcast_addrs_t; typedef enum { - MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED = 1, /* hardware steering */ + MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED = 1, /* HW classification */ MAC_ADDRESS_TYPE_UNICAST_PROMISC /* promiscuous mode */ } mac_address_type_t; +typedef struct mac_vlan_s { + struct mac_vlan_s *mv_next; + uint16_t mv_vid; +} mac_vlan_t; + typedef struct mac_address_s { mac_address_type_t ma_type; /* address type */ - int ma_nusers; /* number of users */ - /* of that address */ + int ma_nusers; /* num users of addr */ struct mac_address_s *ma_next; /* next address */ uint8_t ma_addr[MAXMACADDRLEN]; /* address value */ size_t ma_len; /* address length */ + mac_vlan_t *ma_vlans; /* VLANs on this addr */ + boolean_t ma_untagged; /* accept untagged? */ mac_group_t *ma_group; /* asscociated group */ mac_impl_t *ma_mip; /* MAC handle */ } mac_address_t; @@ -487,7 +498,7 @@ struct mac_impl_s { mac_capab_led_t mi_led; /* - * MAC address list. SL protected. + * MAC address and VLAN lists. SL protected. */ mac_address_t *mi_addresses; @@ -759,6 +770,8 @@ extern void mac_client_bcast_refresh(mac_client_impl_t *, mac_multicst_t, */ extern int mac_group_addmac(mac_group_t *, const uint8_t *); extern int mac_group_remmac(mac_group_t *, const uint8_t *); +extern int mac_group_addvlan(mac_group_t *, uint16_t); +extern int mac_group_remvlan(mac_group_t *, uint16_t); extern int mac_rx_group_add_flow(mac_client_impl_t *, flow_entry_t *, mac_group_t *); extern mblk_t *mac_hwring_tx(mac_ring_handle_t, mblk_t *); @@ -779,6 +792,7 @@ extern void mac_rx_switch_grp_to_sw(mac_group_t *); * MAC address functions are used internally by MAC layer. */ extern mac_address_t *mac_find_macaddr(mac_impl_t *, uint8_t *); +extern mac_address_t *mac_find_macaddr_vlan(mac_impl_t *, uint8_t *, uint16_t); extern boolean_t mac_check_macaddr_shared(mac_address_t *); extern int mac_update_macaddr(mac_address_t *, uint8_t *); extern void mac_freshen_macaddr(mac_address_t *, uint8_t *); @@ -863,8 +877,9 @@ extern int mac_start_group(mac_group_t *); extern void mac_stop_group(mac_group_t *); extern int mac_start_ring(mac_ring_t *); extern void mac_stop_ring(mac_ring_t *); -extern int mac_add_macaddr(mac_impl_t *, mac_group_t *, uint8_t *, boolean_t); -extern int mac_remove_macaddr(mac_address_t *); +extern int mac_add_macaddr_vlan(mac_impl_t *, mac_group_t *, uint8_t *, + uint16_t, boolean_t); +extern int mac_remove_macaddr_vlan(mac_address_t *, uint16_t); extern void mac_set_group_state(mac_group_t *, mac_group_state_t); extern void mac_group_add_client(mac_group_t *, mac_client_impl_t *); diff --git a/usr/src/uts/common/sys/mac_provider.h b/usr/src/uts/common/sys/mac_provider.h index 4c91c03967..301bc9a058 100644 --- a/usr/src/uts/common/sys/mac_provider.h +++ b/usr/src/uts/common/sys/mac_provider.h @@ -21,7 +21,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, Joyent, Inc. + * Copyright (c) 2018, Joyent, Inc. */ #ifndef _SYS_MAC_PROVIDER_H @@ -280,6 +280,28 @@ typedef enum { MAC_RING_TYPE_TX /* Transmit ring */ } mac_ring_type_t; +/* + * The value VLAN_ID_NONE (VID 0) means a client does not have + * membership to any VLAN. However, this statement is true for both + * untagged packets and priority tagged packets leading to confusion + * over what semantic is intended. To the provider, VID 0 is a valid + * VID when priority tagging is in play. To MAC and everything above + * VLAN_ID_NONE almost universally implies untagged traffic. Thus, we + * convert VLAN_ID_NONE to a sentinel value (MAC_VLAN_UNTAGGED) at the + * border between MAC and MAC provider. This informs the provider that + * the client is interested in untagged traffic and the provider + * should set any relevant bits to receive such traffic. + * + * Currently, the API between MAC and the provider passes the VID as a + * unit16_t. In the future this could actually be the entire TCI mask + * (PCP, DEI, and VID). This current scheme is safe in that potential + * future world as well; as 0xFFFF is not a valid TCI (the 0xFFF VID + * is reserved and never transmitted across networks). + */ +#define MAC_VLAN_UNTAGGED UINT16_MAX +#define MAC_VLAN_UNTAGGED_VID(vid) \ + (((vid) == VLAN_ID_NONE) ? MAC_VLAN_UNTAGGED : (vid)) + /* * Grouping type of a ring group * @@ -358,6 +380,8 @@ typedef struct mac_ring_info_s { * #defines for mri_flags. The flags are temporary flags that are provided * only to workaround issues in specific drivers, and they will be * removed in the future. + * + * These are consumed only by sun4v and neptune (nxge). */ #define MAC_RING_TX_SERIALIZE 0x1 #define MAC_RING_RX_ENQUEUE 0x2 @@ -366,6 +390,8 @@ typedef int (*mac_group_start_t)(mac_group_driver_t); typedef void (*mac_group_stop_t)(mac_group_driver_t); typedef int (*mac_add_mac_addr_t)(void *, const uint8_t *); typedef int (*mac_rem_mac_addr_t)(void *, const uint8_t *); +typedef int (*mac_add_vlan_filter_t)(mac_group_driver_t, uint16_t); +typedef int (*mac_rem_vlan_filter_t)(mac_group_driver_t, uint16_t); struct mac_group_info_s { mac_group_driver_t mgi_driver; /* Driver reference */ @@ -374,9 +400,11 @@ struct mac_group_info_s { uint_t mgi_count; /* Count of rings */ mac_intr_t mgi_intr; /* Optional per-group intr */ - /* Only used for rx groups */ + /* Only used for Rx groups */ mac_add_mac_addr_t mgi_addmac; /* Add a MAC address */ mac_rem_mac_addr_t mgi_remmac; /* Remove a MAC address */ + mac_add_vlan_filter_t mgi_addvlan; /* Add a VLAN filter */ + mac_rem_vlan_filter_t mgi_remvlan; /* Remove a VLAN filter */ }; /* @@ -494,14 +522,14 @@ extern void mac_free(mac_register_t *); extern int mac_register(mac_register_t *, mac_handle_t *); extern int mac_disable_nowait(mac_handle_t); extern int mac_disable(mac_handle_t); -extern int mac_unregister(mac_handle_t); -extern void mac_rx(mac_handle_t, mac_resource_handle_t, +extern int mac_unregister(mac_handle_t); +extern void mac_rx(mac_handle_t, mac_resource_handle_t, mblk_t *); -extern void mac_rx_ring(mac_handle_t, mac_ring_handle_t, +extern void mac_rx_ring(mac_handle_t, mac_ring_handle_t, mblk_t *, uint64_t); -extern void mac_link_update(mac_handle_t, link_state_t); -extern void mac_link_redo(mac_handle_t, link_state_t); -extern void mac_unicst_update(mac_handle_t, +extern void mac_link_update(mac_handle_t, link_state_t); +extern void mac_link_redo(mac_handle_t, link_state_t); +extern void mac_unicst_update(mac_handle_t, const uint8_t *); extern void mac_dst_update(mac_handle_t, const uint8_t *); extern void mac_tx_update(mac_handle_t); -- cgit v1.2.3 From 45948e49c407e4fc264fdd289ed632d6639e009d Mon Sep 17 00:00:00 2001 From: Ryan Zezeski Date: Wed, 22 Jan 2020 11:52:39 -0700 Subject: 11493 aggr needs support for multiple pseudo rx groups Portions contributed by: Dan McDonald Reviewed by: Patrick Mooney Reviewed by: Jerry Jelinek Reviewed by: Robert Mustacchi Reviewed by: Paul Winder Approved by: Gordon Ross --- usr/src/cmd/mdb/common/modules/mac/mac.c | 3 + usr/src/uts/common/io/aggr/aggr_grp.c | 426 +++++++++++++++---------- usr/src/uts/common/io/aggr/aggr_port.c | 135 ++++---- usr/src/uts/common/io/aggr/aggr_recv.c | 28 +- usr/src/uts/common/io/mac/mac.c | 237 ++++++++++++-- usr/src/uts/common/io/mac/mac_client.c | 13 +- usr/src/uts/common/io/mac/mac_datapath_setup.c | 98 ++++-- usr/src/uts/common/io/mac/mac_provider.c | 38 ++- usr/src/uts/common/io/mac/mac_stat.c | 22 +- usr/src/uts/common/sys/aggr_impl.h | 56 ++-- usr/src/uts/common/sys/mac_client_priv.h | 13 + usr/src/uts/common/sys/mac_impl.h | 13 +- usr/src/uts/common/sys/mac_provider.h | 54 +++- usr/src/uts/sun4v/io/vnet.c | 19 +- 14 files changed, 800 insertions(+), 355 deletions(-) (limited to 'usr/src/uts/common/sys') diff --git a/usr/src/cmd/mdb/common/modules/mac/mac.c b/usr/src/cmd/mdb/common/modules/mac/mac.c index d42066a37d..1f80e11096 100644 --- a/usr/src/cmd/mdb/common/modules/mac/mac.c +++ b/usr/src/cmd/mdb/common/modules/mac/mac.c @@ -21,6 +21,7 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2018 Joyent, Inc. */ #include @@ -967,6 +968,8 @@ mac_ring_classify2str(mac_classify_type_t classify) return ("sw"); case MAC_HW_CLASSIFIER: return ("hw"); + case MAC_PASSTHRU_CLASSIFIER: + return ("pass"); } return ("--"); } diff --git a/usr/src/uts/common/io/aggr/aggr_grp.c b/usr/src/uts/common/io/aggr/aggr_grp.c index 9932c2cb58..48cdc241d6 100644 --- a/usr/src/uts/common/io/aggr/aggr_grp.c +++ b/usr/src/uts/common/io/aggr/aggr_grp.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2018 Joyent, Inc. + * Copyright 2020 Joyent, Inc. */ /* @@ -32,39 +32,69 @@ * module. The hash key is the linkid associated with the link * aggregation group. * - * A set of MAC ports are associated with each association group. + * Each aggregation contains a set of ports. The port is represented + * by the aggr_port_t structure. A port consists of a single MAC + * client which has exclusive (MCIS_EXCLUSIVE) use of the underlying + * MAC. This client is used by the aggr to send and receive LACP + * traffic. Each port client takes on the same MAC unicast address -- + * the address of the aggregation itself (taken from the first port by + * default). * - * Aggr pseudo TX rings - * -------------------- - * The underlying ports (NICs) in an aggregation can have TX rings. To - * enhance aggr's performance, these TX rings are made available to the - * aggr layer as pseudo TX rings. The concept of pseudo rings are not new. - * They are already present and implemented on the RX side. It is called - * as pseudo RX rings. The same concept is extended to the TX side where - * each TX ring of an underlying port is reflected in aggr as a pseudo - * TX ring. Thus each pseudo TX ring will map to a specific hardware TX - * ring. Even in the case of a NIC that does not have a TX ring, a pseudo - * TX ring is given to the aggregation layer. + * The MAC client that hangs off each aggr port is not your typical + * MAC client. Not only does it have exclusive control of the MAC, but + * it also has no Tx or Rx SRSes. An SRS is designed to queue and + * fanout traffic among L4 protocols; but the aggr is an intermediary, + * not a consumer. Instead of using SRSes, the aggr puts the + * underlying hardware rings into passthru mode and ships packets up + * via a direct call to aggr_recv_cb(). This allows aggr to enforce + * LACP while passing all other traffic up to clients of the aggr. + * + * Pseudo Rx Groups and Rings + * -------------------------- + * + * It is imperative for client performance that the aggr provide as + * many MAC groups as possible. In order to use the underlying HW + * resources, aggr creates pseudo groups to aggregate the underlying + * HW groups. Every HW group gets mapped to a pseudo group; and every + * HW ring in that group gets mapped to a pseudo ring. The pseudo + * group at index 0 combines all the HW groups at index 0 from each + * port, etc. The aggr's MAC then creates normal MAC groups and rings + * out of these pseudo groups and rings to present to the aggr's + * clients. To the clients, the aggr's groups and rings are absolutely + * no different than a NIC's groups or rings. + * + * Pseudo Tx Rings + * --------------- + * + * The underlying ports (NICs) in an aggregation can have Tx rings. To + * enhance aggr's performance, these Tx rings are made available to + * the aggr layer as pseudo Tx rings. The concept of pseudo rings are + * not new. They are already present and implemented on the Rx side. + * The same concept is extended to the Tx side where each Tx ring of + * an underlying port is reflected in aggr as a pseudo Tx ring. Thus + * each pseudo Tx ring will map to a specific hardware Tx ring. Even + * in the case of a NIC that does not have a Tx ring, a pseudo Tx ring + * is given to the aggregation layer. * * With this change, the outgoing stack depth looks much better: * * mac_tx() -> mac_tx_aggr_mode() -> mac_tx_soft_ring_process() -> * mac_tx_send() -> aggr_ring_rx() -> _ring_tx() * - * Two new modes are introduced to mac_tx() to handle aggr pseudo TX rings: + * Two new modes are introduced to mac_tx() to handle aggr pseudo Tx rings: * SRS_TX_AGGR and SRS_TX_BW_AGGR. * * In SRS_TX_AGGR mode, mac_tx_aggr_mode() routine is called. This routine - * invokes an aggr function, aggr_find_tx_ring(), to find a (pseudo) TX + * invokes an aggr function, aggr_find_tx_ring(), to find a (pseudo) Tx * ring belonging to a port on which the packet has to be sent. * aggr_find_tx_ring() first finds the outgoing port based on L2/L3/L4 - * policy and then uses the fanout_hint passed to it to pick a TX ring from + * policy and then uses the fanout_hint passed to it to pick a Tx ring from * the selected port. * * In SRS_TX_BW_AGGR mode, mac_tx_bw_mode() function is called where * bandwidth limit is applied first on the outgoing packet and the packets * allowed to go out would call mac_tx_aggr_mode() to send the packet on a - * particular TX ring. + * particular Tx ring. */ #include @@ -121,7 +151,8 @@ static int aggr_add_pseudo_rx_group(aggr_port_t *, aggr_pseudo_rx_group_t *); static void aggr_rem_pseudo_rx_group(aggr_port_t *, aggr_pseudo_rx_group_t *); static int aggr_pseudo_disable_intr(mac_intr_handle_t); static int aggr_pseudo_enable_intr(mac_intr_handle_t); -static int aggr_pseudo_start_ring(mac_ring_driver_t, uint64_t); +static int aggr_pseudo_start_rx_ring(mac_ring_driver_t, uint64_t); +static void aggr_pseudo_stop_rx_ring(mac_ring_driver_t); static int aggr_addmac(void *, const uint8_t *); static int aggr_remmac(void *, const uint8_t *); static int aggr_addvlan(mac_group_driver_t, uint16_t); @@ -366,9 +397,13 @@ aggr_grp_attach_port(aggr_grp_t *grp, aggr_port_t *port) aggr_grp_multicst_port(port, B_TRUE); /* - * Set port's receive callback + * The port client doesn't have an Rx SRS; instead of calling + * mac_rx_set() we set the client's flow callback directly. + * This datapath is used only when the port's driver doesn't + * support MAC_CAPAB_RINGS. Drivers with ring support will + * deliver traffic to the aggr via ring passthru. */ - mac_rx_set(port->lp_mch, aggr_recv_cb, port); + mac_client_set_flow_cb(port->lp_mch, aggr_recv_cb, port); /* * If LACP is OFF, the port can be used to send data as soon @@ -398,7 +433,7 @@ aggr_grp_detach_port(aggr_grp_t *grp, aggr_port_t *port) if (port->lp_state != AGGR_PORT_STATE_ATTACHED) return (B_FALSE); - mac_rx_clear(port->lp_mch); + mac_client_clear_flow_cb(port->lp_mch); aggr_grp_multicst_port(port, B_FALSE); @@ -537,26 +572,27 @@ aggr_grp_add_port(aggr_grp_t *grp, datalink_id_t port_linkid, boolean_t force, zoneid_t port_zoneid = ALL_ZONES; int err; - /* The port must be int the same zone as the aggregation. */ + /* The port must be in the same zone as the aggregation. */ if (zone_check_datalink(&port_zoneid, port_linkid) != 0) port_zoneid = GLOBAL_ZONEID; if (grp->lg_zoneid != port_zoneid) return (EBUSY); /* - * lg_mh could be NULL when the function is called during the creation - * of the aggregation. + * If we are creating the aggr, then there is no MAC handle + * and thus no perimeter to hold. If we are adding a port to + * an existing aggr, then the perimiter of the aggr's MAC must + * be held. */ ASSERT(grp->lg_mh == NULL || MAC_PERIM_HELD(grp->lg_mh)); - /* create new port */ err = aggr_port_create(grp, port_linkid, force, &port); if (err != 0) return (err); mac_perim_enter_by_mh(port->lp_mh, &mph); - /* add port to list of group constituent ports */ + /* Add the new port to the end of the list. */ cport = &grp->lg_ports; while (*cport != NULL) cport = &((*cport)->lp_next); @@ -638,6 +674,7 @@ aggr_add_pseudo_rx_ring(aggr_port_t *port, ring->arr_flags |= MAC_PSEUDO_RING_INUSE; ring->arr_hw_rh = hw_rh; ring->arr_port = port; + ring->arr_grp = rx_grp; rx_grp->arg_ring_cnt++; /* @@ -648,10 +685,15 @@ aggr_add_pseudo_rx_ring(aggr_port_t *port, ring->arr_flags &= ~MAC_PSEUDO_RING_INUSE; ring->arr_hw_rh = NULL; ring->arr_port = NULL; + ring->arr_grp = NULL; rx_grp->arg_ring_cnt--; } else { - mac_hwring_setup(hw_rh, (mac_resource_handle_t)ring, - mac_find_ring(rx_grp->arg_gh, j)); + /* + * This must run after the MAC is registered. + */ + ASSERT3P(ring->arr_rh, !=, NULL); + mac_hwring_set_passthru(hw_rh, (mac_rx_t)aggr_recv_cb, + (void *)port, (mac_resource_handle_t)ring); } return (err); } @@ -662,11 +704,9 @@ aggr_add_pseudo_rx_ring(aggr_port_t *port, static void aggr_rem_pseudo_rx_ring(aggr_pseudo_rx_group_t *rx_grp, mac_ring_handle_t hw_rh) { - aggr_pseudo_rx_ring_t *ring; - int j; + for (uint_t j = 0; j < MAX_RINGS_PER_GROUP; j++) { + aggr_pseudo_rx_ring_t *ring = rx_grp->arg_rings + j; - for (j = 0; j < MAX_RINGS_PER_GROUP; j++) { - ring = rx_grp->arg_rings + j; if (!(ring->arr_flags & MAC_PSEUDO_RING_INUSE) || ring->arr_hw_rh != hw_rh) { continue; @@ -677,8 +717,9 @@ aggr_rem_pseudo_rx_ring(aggr_pseudo_rx_group_t *rx_grp, mac_ring_handle_t hw_rh) ring->arr_flags &= ~MAC_PSEUDO_RING_INUSE; ring->arr_hw_rh = NULL; ring->arr_port = NULL; + ring->arr_grp = NULL; rx_grp->arg_ring_cnt--; - mac_hwring_teardown(hw_rh); + mac_hwring_clear_passthru(hw_rh); break; } } @@ -695,52 +736,41 @@ aggr_rem_pseudo_rx_ring(aggr_pseudo_rx_group_t *rx_grp, mac_ring_handle_t hw_rh) static int aggr_add_pseudo_rx_group(aggr_port_t *port, aggr_pseudo_rx_group_t *rx_grp) { - aggr_grp_t *grp = port->lp_grp; mac_ring_handle_t hw_rh[MAX_RINGS_PER_GROUP]; aggr_unicst_addr_t *addr, *a; mac_perim_handle_t pmph; aggr_vlan_t *avp; - int hw_rh_cnt, i = 0, j; + uint_t hw_rh_cnt, i; int err = 0; + uint_t g_idx = rx_grp->arg_index; - ASSERT(MAC_PERIM_HELD(grp->lg_mh)); + ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); + ASSERT3U(g_idx, <, MAX_GROUPS_PER_PORT); mac_perim_enter_by_mh(port->lp_mh, &pmph); /* - * This function must be called after the aggr registers its MAC - * and its Rx group has been initialized. + * This function must be called after the aggr registers its + * MAC and its Rx groups have been initialized. */ ASSERT(rx_grp->arg_gh != NULL); /* * Get the list of the underlying HW rings. */ - hw_rh_cnt = mac_hwrings_get(port->lp_mch, - &port->lp_hwgh, hw_rh, MAC_RING_TYPE_RX); - - if (port->lp_hwgh != NULL) { - /* - * Quiesce the HW ring and the MAC SRS on the ring. Note - * that the HW ring will be restarted when the pseudo ring - * is started. At that time all the packets will be - * directly passed up to the pseudo Rx ring and handled - * by MAC SRS created over the pseudo Rx ring. - */ - mac_rx_client_quiesce(port->lp_mch); - mac_srs_perm_quiesce(port->lp_mch, B_TRUE); - } + hw_rh_cnt = mac_hwrings_idx_get(port->lp_mh, g_idx, + &port->lp_hwghs[g_idx], hw_rh, MAC_RING_TYPE_RX); /* * Add existing VLAN and unicast address filters to the port. */ for (avp = list_head(&rx_grp->arg_vlans); avp != NULL; avp = list_next(&rx_grp->arg_vlans, avp)) { - if ((err = aggr_port_addvlan(port, avp->av_vid)) != 0) + if ((err = aggr_port_addvlan(port, g_idx, avp->av_vid)) != 0) goto err; } for (addr = rx_grp->arg_macaddr; addr != NULL; addr = addr->aua_next) { - if ((err = aggr_port_addmac(port, addr->aua_addr)) != 0) + if ((err = aggr_port_addmac(port, g_idx, addr->aua_addr)) != 0) goto err; } @@ -750,18 +780,17 @@ aggr_add_pseudo_rx_group(aggr_port_t *port, aggr_pseudo_rx_group_t *rx_grp) goto err; } - port->lp_rx_grp_added = B_TRUE; mac_perim_exit(pmph); return (0); err: ASSERT(err != 0); - for (j = 0; j < i; j++) + for (uint_t j = 0; j < i; j++) aggr_rem_pseudo_rx_ring(rx_grp, hw_rh[j]); for (a = rx_grp->arg_macaddr; a != addr; a = a->aua_next) - aggr_port_remmac(port, a->aua_addr); + aggr_port_remmac(port, g_idx, a->aua_addr); if (avp != NULL) avp = list_prev(&rx_grp->arg_vlans, avp); @@ -769,19 +798,14 @@ err: for (; avp != NULL; avp = list_prev(&rx_grp->arg_vlans, avp)) { int err2; - if ((err2 = aggr_port_remvlan(port, avp->av_vid)) != 0) { + if ((err2 = aggr_port_remvlan(port, g_idx, avp->av_vid)) != 0) { cmn_err(CE_WARN, "Failed to remove VLAN %u from port %s" ": errno %d.", avp->av_vid, mac_client_name(port->lp_mch), err2); } } - if (port->lp_hwgh != NULL) { - mac_srs_perm_quiesce(port->lp_mch, B_FALSE); - mac_rx_client_restart(port->lp_mch); - port->lp_hwgh = NULL; - } - + port->lp_hwghs[g_idx] = NULL; mac_perim_exit(pmph); return (err); } @@ -795,55 +819,38 @@ err: static void aggr_rem_pseudo_rx_group(aggr_port_t *port, aggr_pseudo_rx_group_t *rx_grp) { - aggr_grp_t *grp = port->lp_grp; mac_ring_handle_t hw_rh[MAX_RINGS_PER_GROUP]; aggr_unicst_addr_t *addr; - mac_group_handle_t hwgh; mac_perim_handle_t pmph; - int hw_rh_cnt, i; + uint_t hw_rh_cnt; + uint_t g_idx = rx_grp->arg_index; - ASSERT(MAC_PERIM_HELD(grp->lg_mh)); + ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); + ASSERT3U(g_idx, <, MAX_GROUPS_PER_PORT); + ASSERT3P(rx_grp->arg_gh, !=, NULL); mac_perim_enter_by_mh(port->lp_mh, &pmph); - if (!port->lp_rx_grp_added) - goto done; - - ASSERT(rx_grp->arg_gh != NULL); - hw_rh_cnt = mac_hwrings_get(port->lp_mch, - &hwgh, hw_rh, MAC_RING_TYPE_RX); + hw_rh_cnt = mac_hwrings_idx_get(port->lp_mh, g_idx, NULL, hw_rh, + MAC_RING_TYPE_RX); - for (i = 0; i < hw_rh_cnt; i++) + for (uint_t i = 0; i < hw_rh_cnt; i++) aggr_rem_pseudo_rx_ring(rx_grp, hw_rh[i]); for (addr = rx_grp->arg_macaddr; addr != NULL; addr = addr->aua_next) - aggr_port_remmac(port, addr->aua_addr); + aggr_port_remmac(port, g_idx, addr->aua_addr); for (aggr_vlan_t *avp = list_head(&rx_grp->arg_vlans); avp != NULL; avp = list_next(&rx_grp->arg_vlans, avp)) { int err; - if ((err = aggr_port_remvlan(port, avp->av_vid)) != 0) { + if ((err = aggr_port_remvlan(port, g_idx, avp->av_vid)) != 0) { cmn_err(CE_WARN, "Failed to remove VLAN %u from port %s" ": errno %d.", avp->av_vid, mac_client_name(port->lp_mch), err); } } - if (port->lp_hwgh != NULL) { - port->lp_hwgh = NULL; - - /* - * First clear the permanent-quiesced flag of the RX srs then - * restart the HW ring and the mac srs on the ring. Note that - * the HW ring and associated SRS will soon been removed when - * the port is removed from the aggr. - */ - mac_srs_perm_quiesce(port->lp_mch, B_FALSE); - mac_rx_client_restart(port->lp_mch); - } - - port->lp_rx_grp_added = B_FALSE; -done: + port->lp_hwghs[g_idx] = NULL; mac_perim_exit(pmph); } @@ -947,8 +954,8 @@ aggr_add_pseudo_tx_group(aggr_port_t *port, aggr_pseudo_tx_group_t *tx_grp) /* * Get the list the the underlying HW rings. */ - hw_rh_cnt = mac_hwrings_get(port->lp_mch, - NULL, hw_rh, MAC_RING_TYPE_TX); + hw_rh_cnt = mac_hwrings_get(port->lp_mch, NULL, hw_rh, + MAC_RING_TYPE_TX); /* * Even if the underlying NIC does not have TX rings, we @@ -1054,21 +1061,45 @@ aggr_pseudo_enable_intr(mac_intr_handle_t ih) } /* - * Here we need to start the pseudo-ring. As MAC already ensures that the - * underlying device is set up, all we need to do is save the ring generation. - * - * Note, we don't end up wanting to use the underlying mac_hwring_start/stop - * functions here as those don't actually stop and start the ring, they just - * quiesce the ring. Regardless of whether the aggr is logically up or not, we - * want to make sure that we can receive traffic for LACP. + * Start the pseudo ring. Since the pseudo ring is just an abstraction + * over an actual HW ring, the real task is to start the underlying HW + * ring. */ static int -aggr_pseudo_start_ring(mac_ring_driver_t arg, uint64_t mr_gen) +aggr_pseudo_start_rx_ring(mac_ring_driver_t arg, uint64_t mr_gen) { + int err; aggr_pseudo_rx_ring_t *rr_ring = (aggr_pseudo_rx_ring_t *)arg; + err = mac_hwring_start(rr_ring->arr_hw_rh); + + if (err != 0) + return (err); + rr_ring->arr_gen = mr_gen; - return (0); + return (err); +} + +/* + * Stop the pseudo ring. Since the pseudo ring is just an abstraction + * over an actual HW ring, the real task is to stop the underlying HW + * ring. + */ +static void +aggr_pseudo_stop_rx_ring(mac_ring_driver_t arg) +{ + aggr_pseudo_rx_ring_t *rr_ring = (aggr_pseudo_rx_ring_t *)arg; + + /* + * The rings underlying the default group must stay up to + * continue receiving LACP traffic. We would normally never + * stop the default Rx rings because of the primary MAC + * client; but aggr's primary MAC client doesn't call + * mac_unicast_add() and thus mi_active is 0 when the last + * non-primary client is deleted. + */ + if (rr_ring->arr_grp->arg_index != 0) + mac_hwring_stop(rr_ring->arr_hw_rh); } /* @@ -1078,13 +1109,15 @@ int aggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force, laioc_port_t *ports) { - int rc, i, nadded = 0; + int rc; + uint_t port_added = 0; + uint_t grp_added; aggr_grp_t *grp = NULL; aggr_port_t *port; boolean_t link_state_changed = B_FALSE; mac_perim_handle_t mph, pmph; - /* get group corresponding to linkid */ + /* Get the aggr corresponding to linkid. */ rw_enter(&aggr_grp_lock, RW_READER); if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid), (mod_hash_val_t *)&grp) != 0) { @@ -1094,20 +1127,22 @@ aggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force, AGGR_GRP_REFHOLD(grp); /* - * Hold the perimeter so that the aggregation won't be destroyed. + * Hold the perimeter so that the aggregation can't be destroyed. */ mac_perim_enter_by_mh(grp->lg_mh, &mph); rw_exit(&aggr_grp_lock); - /* add the specified ports to group */ - for (i = 0; i < nports; i++) { - /* add port to group */ + /* Add the specified ports to the aggr. */ + for (uint_t i = 0; i < nports; i++) { + grp_added = 0; + if ((rc = aggr_grp_add_port(grp, ports[i].lp_linkid, force, &port)) != 0) { goto bail; } + ASSERT(port != NULL); - nadded++; + port_added++; /* check capabilities */ if (!aggr_grp_capab_check(grp, port) || @@ -1124,9 +1159,16 @@ aggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force, rc = aggr_add_pseudo_tx_group(port, &grp->lg_tx_group); if (rc != 0) goto bail; - rc = aggr_add_pseudo_rx_group(port, &grp->lg_rx_group); - if (rc != 0) - goto bail; + + for (uint_t j = 0; j < grp->lg_rx_group_count; j++) { + rc = aggr_add_pseudo_rx_group(port, + &grp->lg_rx_groups[j]); + + if (rc != 0) + goto bail; + + grp_added++; + } mac_perim_enter_by_mh(port->lp_mh, &pmph); @@ -1144,7 +1186,7 @@ aggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force, /* * Turn on the promiscuous mode over the port when it * is requested to be turned on to receive the - * non-primary address over a port, or the promiscous + * non-primary address over a port, or the promiscuous * mode is enabled over the aggr. */ if (grp->lg_promisc || port->lp_prom_addr != NULL) { @@ -1179,17 +1221,33 @@ aggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force, bail: if (rc != 0) { /* stop and remove ports that have been added */ - for (i = 0; i < nadded; i++) { + for (uint_t i = 0; i < port_added; i++) { + uint_t grp_remove; + port = aggr_grp_port_lookup(grp, ports[i].lp_linkid); ASSERT(port != NULL); + if (grp->lg_started) { mac_perim_enter_by_mh(port->lp_mh, &pmph); (void) aggr_port_promisc(port, B_FALSE); aggr_port_stop(port); mac_perim_exit(pmph); } + aggr_rem_pseudo_tx_group(port, &grp->lg_tx_group); - aggr_rem_pseudo_rx_group(port, &grp->lg_rx_group); + + /* + * Only the last port could have a partial set + * of groups added. + */ + grp_remove = (i + 1 == port_added) ? grp_added : + grp->lg_rx_group_count; + + for (uint_t j = 0; j < grp_remove; j++) { + aggr_rem_pseudo_rx_group(port, + &grp->lg_rx_groups[j]); + } + (void) aggr_grp_rem_port(grp, port, NULL, NULL); } } @@ -1351,14 +1409,11 @@ aggr_grp_create(datalink_id_t linkid, uint32_t key, uint_t nports, grp->lg_tx_blocked_rings = kmem_zalloc((sizeof (mac_ring_handle_t *) * MAX_RINGS_PER_GROUP), KM_SLEEP); grp->lg_tx_blocked_cnt = 0; - bzero(&grp->lg_rx_group, sizeof (aggr_pseudo_rx_group_t)); + bzero(&grp->lg_rx_groups, + sizeof (aggr_pseudo_rx_group_t) * MAX_GROUPS_PER_PORT); bzero(&grp->lg_tx_group, sizeof (aggr_pseudo_tx_group_t)); aggr_lacp_init_grp(grp); - grp->lg_rx_group.arg_untagged = 0; - list_create(&(grp->lg_rx_group.arg_vlans), sizeof (aggr_vlan_t), - offsetof(aggr_vlan_t, av_link)); - /* add MAC ports to group */ grp->lg_ports = NULL; grp->lg_nports = 0; @@ -1380,6 +1435,42 @@ aggr_grp_create(datalink_id_t linkid, uint32_t key, uint_t nports, goto bail; } + grp->lg_rx_group_count = 1; + + for (port = grp->lg_ports; port != NULL; port = port->lp_next) { + uint_t num_rgroups; + + mac_perim_enter_by_mh(port->lp_mh, &mph); + num_rgroups = mac_get_num_rx_groups(port->lp_mh); + mac_perim_exit(mph); + + /* + * Utilize all the groups in a port. If some ports + * have less groups than others, then traffic destined + * for the same unicast address may be HW classified + * on some ports but SW classified by aggr when + * arriving on other ports. + */ + grp->lg_rx_group_count = MAX(grp->lg_rx_group_count, + num_rgroups); + } + + /* + * There could be cases where the hardware provides more + * groups than aggr can support. Make sure we never go above + * the max aggr can support. + */ + grp->lg_rx_group_count = MIN(grp->lg_rx_group_count, + MAX_GROUPS_PER_PORT); + + ASSERT3U(grp->lg_rx_group_count, >, 0); + for (i = 0; i < MAX_GROUPS_PER_PORT; i++) { + grp->lg_rx_groups[i].arg_index = i; + grp->lg_rx_groups[i].arg_untagged = 0; + list_create(&(grp->lg_rx_groups[i].arg_vlans), + sizeof (aggr_vlan_t), offsetof(aggr_vlan_t, av_link)); + } + /* * If no explicit MAC address was specified by the administrator, * set it to the MAC address of the first port. @@ -1397,7 +1488,7 @@ aggr_grp_create(datalink_id_t linkid, uint32_t key, uint_t nports, grp->lg_mac_addr_port = grp->lg_ports; } - /* set the initial group capabilities */ + /* Set the initial group capabilities. */ aggr_grp_capab_set(grp); if ((mac = mac_alloc(MAC_VERSION)) == NULL) { @@ -1432,14 +1523,18 @@ aggr_grp_create(datalink_id_t linkid, uint32_t key, uint_t nports, * Update the MAC address of the constituent ports. * None of the port is attached at this time, the link state of the * aggregation will not change. + * + * All ports take on the primary MAC address of the aggr + * (lg_aggr). At this point, none of the ports are attached; + * thus the link state of the aggregation will not change. */ link_state_changed = aggr_grp_update_ports_mac(grp); ASSERT(!link_state_changed); - /* update outbound load balancing policy */ + /* Update outbound load balancing policy. */ aggr_send_update_policy(grp, policy); - /* set LACP mode */ + /* Set LACP mode. */ aggr_lacp_set_mode(grp, lacp_mode, lacp_timer); /* @@ -1447,12 +1542,18 @@ aggr_grp_create(datalink_id_t linkid, uint32_t key, uint_t nports, */ for (port = grp->lg_ports; port != NULL; port = port->lp_next) { /* - * Create the pseudo ring for each HW ring of the underlying - * port. Note that this is done after the aggr registers the - * mac. + * Create the pseudo ring for each HW ring of the + * underlying port. Note that this is done after the + * aggr registers its MAC. */ - VERIFY(aggr_add_pseudo_tx_group(port, &grp->lg_tx_group) == 0); - VERIFY(aggr_add_pseudo_rx_group(port, &grp->lg_rx_group) == 0); + VERIFY3S(aggr_add_pseudo_tx_group(port, &grp->lg_tx_group), + ==, 0); + + for (i = 0; i < grp->lg_rx_group_count; i++) { + VERIFY3S(aggr_add_pseudo_rx_group(port, + &grp->lg_rx_groups[i]), ==, 0); + } + if (aggr_port_notify_link(grp, port)) link_state_changed = B_TRUE; @@ -1734,7 +1835,8 @@ aggr_grp_rem_ports(datalink_id_t linkid, uint_t nports, laioc_port_t *ports) * aggr_find_tx_ring() will not return any rings * belonging to it. */ - aggr_rem_pseudo_rx_group(port, &grp->lg_rx_group); + for (i = 0; i < grp->lg_rx_group_count; i++) + aggr_rem_pseudo_rx_group(port, &grp->lg_rx_groups[i]); /* remove port from group */ rc = aggr_grp_rem_port(grp, port, &mac_addr_changed, @@ -1839,7 +1941,8 @@ aggr_grp_delete(datalink_id_t linkid, cred_t *cred) (void) aggr_grp_detach_port(grp, port); mac_perim_exit(pmph); aggr_rem_pseudo_tx_group(port, &grp->lg_tx_group); - aggr_rem_pseudo_rx_group(port, &grp->lg_rx_group); + for (uint_t i = 0; i < grp->lg_rx_group_count; i++) + aggr_rem_pseudo_rx_group(port, &grp->lg_rx_groups[i]); aggr_port_delete(port); port = cport; } @@ -1858,7 +1961,9 @@ aggr_grp_delete(datalink_id_t linkid, cred_t *cred) VERIFY(mac_unregister(grp->lg_mh) == 0); grp->lg_mh = NULL; - list_destroy(&(grp->lg_rx_group.arg_vlans)); + for (uint_t i = 0; i < MAX_GROUPS_PER_PORT; i++) { + list_destroy(&(grp->lg_rx_groups[i].arg_vlans)); + } AGGR_GRP_REFRELE(grp); return (0); @@ -2224,17 +2329,15 @@ aggr_m_capab_get(void *arg, mac_capab_t cap, void *cap_data) return (!grp->lg_zcopy); case MAC_CAPAB_RINGS: { mac_capab_rings_t *cap_rings = cap_data; + uint_t ring_cnt = 0; + + for (uint_t i = 0; i < grp->lg_rx_group_count; i++) + ring_cnt += grp->lg_rx_groups[i].arg_ring_cnt; if (cap_rings->mr_type == MAC_RING_TYPE_RX) { cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; - cap_rings->mr_rnum = grp->lg_rx_group.arg_ring_cnt; - - /* - * An aggregation advertises only one (pseudo) RX - * group, which virtualizes the main/primary group of - * the underlying devices. - */ - cap_rings->mr_gnum = 1; + cap_rings->mr_rnum = ring_cnt; + cap_rings->mr_gnum = grp->lg_rx_group_count; cap_rings->mr_gaddring = NULL; cap_rings->mr_gremring = NULL; } else { @@ -2273,12 +2376,10 @@ aggr_fill_group(void *arg, mac_ring_type_t rtype, const int index, mac_group_info_t *infop, mac_group_handle_t gh) { aggr_grp_t *grp = arg; - aggr_pseudo_rx_group_t *rx_group; - aggr_pseudo_tx_group_t *tx_group; - ASSERT(index == 0); if (rtype == MAC_RING_TYPE_RX) { - rx_group = &grp->lg_rx_group; + aggr_pseudo_rx_group_t *rx_group = &grp->lg_rx_groups[index]; + rx_group->arg_gh = gh; rx_group->arg_grp = grp; @@ -2297,7 +2398,9 @@ aggr_fill_group(void *arg, mac_ring_type_t rtype, const int index, infop->mgi_addvlan = aggr_addvlan; infop->mgi_remvlan = aggr_remvlan; } else { - tx_group = &grp->lg_tx_group; + aggr_pseudo_tx_group_t *tx_group = &grp->lg_tx_group; + + ASSERT3S(index, ==, 0); tx_group->atg_gh = gh; } } @@ -2313,13 +2416,13 @@ aggr_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index, switch (rtype) { case MAC_RING_TYPE_RX: { - aggr_pseudo_rx_group_t *rx_group = &grp->lg_rx_group; + aggr_pseudo_rx_group_t *rx_group; aggr_pseudo_rx_ring_t *rx_ring; mac_intr_t aggr_mac_intr; - ASSERT(rg_index == 0); - - ASSERT((index >= 0) && (index < rx_group->arg_ring_cnt)); + rx_group = &grp->lg_rx_groups[rg_index]; + ASSERT3S(index, >=, 0); + ASSERT3S(index, <, rx_group->arg_ring_cnt); rx_ring = rx_group->arg_rings + index; rx_ring->arr_rh = rh; @@ -2333,8 +2436,8 @@ aggr_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index, aggr_mac_intr.mi_ddi_handle = NULL; infop->mri_driver = (mac_ring_driver_t)rx_ring; - infop->mri_start = aggr_pseudo_start_ring; - infop->mri_stop = NULL; + infop->mri_start = aggr_pseudo_start_rx_ring; + infop->mri_stop = aggr_pseudo_stop_rx_ring; infop->mri_intr = aggr_mac_intr; infop->mri_poll = aggr_rx_poll; @@ -2421,6 +2524,7 @@ aggr_addmac(void *arg, const uint8_t *mac_addr) aggr_port_t *port, *p; mac_perim_handle_t mph; int err = 0; + uint_t idx = rx_group->arg_index; mac_perim_enter_by_mh(grp->lg_mh, &mph); @@ -2447,12 +2551,12 @@ aggr_addmac(void *arg, const uint8_t *mac_addr) *pprev = addr; for (port = grp->lg_ports; port != NULL; port = port->lp_next) - if ((err = aggr_port_addmac(port, mac_addr)) != 0) + if ((err = aggr_port_addmac(port, idx, mac_addr)) != 0) break; if (err != 0) { for (p = grp->lg_ports; p != port; p = p->lp_next) - aggr_port_remmac(p, mac_addr); + aggr_port_remmac(p, idx, mac_addr); *pprev = NULL; kmem_free(addr, sizeof (aggr_unicst_addr_t)); @@ -2497,7 +2601,7 @@ aggr_remmac(void *arg, const uint8_t *mac_addr) } for (port = grp->lg_ports; port != NULL; port = port->lp_next) - aggr_port_remmac(port, mac_addr); + aggr_port_remmac(port, rx_group->arg_index, mac_addr); *pprev = addr->aua_next; kmem_free(addr, sizeof (aggr_unicst_addr_t)); @@ -2533,12 +2637,13 @@ aggr_find_vlan(aggr_pseudo_rx_group_t *rx_group, uint16_t vid) static int aggr_addvlan(mac_group_driver_t gdriver, uint16_t vid) { - aggr_pseudo_rx_group_t *rx_group = (aggr_pseudo_rx_group_t *)gdriver; + aggr_pseudo_rx_group_t *rx_group = (aggr_pseudo_rx_group_t *)gdriver; aggr_grp_t *aggr = rx_group->arg_grp; aggr_port_t *port, *p; mac_perim_handle_t mph; int err = 0; aggr_vlan_t *avp = NULL; + uint_t idx = rx_group->arg_index; mac_perim_enter_by_mh(aggr->lg_mh, &mph); @@ -2568,7 +2673,7 @@ aggr_addvlan(mac_group_driver_t gdriver, uint16_t vid) update_ports: for (port = aggr->lg_ports; port != NULL; port = port->lp_next) - if ((err = aggr_port_addvlan(port, vid)) != 0) + if ((err = aggr_port_addvlan(port, idx, vid)) != 0) break; if (err != 0) { @@ -2581,7 +2686,7 @@ update_ports: for (p = aggr->lg_ports; p != port; p = p->lp_next) { int err2; - if ((err2 = aggr_port_remvlan(p, vid)) != 0) { + if ((err2 = aggr_port_remvlan(p, idx, vid)) != 0) { cmn_err(CE_WARN, "Failed to remove VLAN %u" " from port %s: errno %d.", vid, mac_client_name(p->lp_mch), err2); @@ -2612,12 +2717,13 @@ done: static int aggr_remvlan(mac_group_driver_t gdriver, uint16_t vid) { - aggr_pseudo_rx_group_t *rx_group = (aggr_pseudo_rx_group_t *)gdriver; + aggr_pseudo_rx_group_t *rx_group = (aggr_pseudo_rx_group_t *)gdriver; aggr_grp_t *aggr = rx_group->arg_grp; aggr_port_t *port, *p; mac_perim_handle_t mph; int err = 0; aggr_vlan_t *avp = NULL; + uint_t idx = rx_group->arg_index; mac_perim_enter_by_mh(aggr->lg_mh, &mph); @@ -2648,7 +2754,7 @@ aggr_remvlan(mac_group_driver_t gdriver, uint16_t vid) update_ports: for (port = aggr->lg_ports; port != NULL; port = port->lp_next) - if ((err = aggr_port_remvlan(port, vid)) != 0) + if ((err = aggr_port_remvlan(port, idx, vid)) != 0) break; /* @@ -2659,7 +2765,7 @@ update_ports: for (p = aggr->lg_ports; p != port; p = p->lp_next) { int err2; - if ((err2 = aggr_port_addvlan(p, vid)) != 0) { + if ((err2 = aggr_port_addvlan(p, idx, vid)) != 0) { cmn_err(CE_WARN, "Failed to add VLAN %u" " to port %s: errno %d.", vid, mac_client_name(p->lp_mch), err2); diff --git a/usr/src/uts/common/io/aggr/aggr_port.c b/usr/src/uts/common/io/aggr/aggr_port.c index 9d2edd4f97..e764dd104e 100644 --- a/usr/src/uts/common/io/aggr/aggr_port.c +++ b/usr/src/uts/common/io/aggr/aggr_port.c @@ -71,10 +71,10 @@ aggr_port_destructor(void *buf, void *arg) { aggr_port_t *port = buf; - ASSERT(port->lp_mnh == NULL); - ASSERT(port->lp_mphp == NULL); - ASSERT(!port->lp_rx_grp_added && !port->lp_tx_grp_added); - ASSERT(port->lp_hwgh == NULL); + ASSERT3P(port->lp_mnh, ==, NULL); + ASSERT(!port->lp_tx_grp_added); + for (uint_t i = 0; i < MAX_GROUPS_PER_PORT; i++) + ASSERT3P(port->lp_hwghs[i], ==, NULL); } void @@ -128,7 +128,6 @@ aggr_port_init_callbacks(aggr_port_t *port) aggr_grp_port_hold(port); } -/* ARGSUSED */ int aggr_port_create(aggr_grp_t *grp, const datalink_id_t linkid, boolean_t force, aggr_port_t **pp) @@ -197,9 +196,9 @@ aggr_port_create(aggr_grp_t *grp, const datalink_id_t linkid, boolean_t force, } /* - * As the underlying mac's current margin size is used to determine + * As the underlying MAC's current margin size is used to determine * the margin size of the aggregation itself, request the underlying - * mac not to change to a smaller size. + * MAC not to change to a smaller size. */ if ((err = mac_margin_add(mh, &margin, B_TRUE)) != 0) { id_free(aggr_portids, portid); @@ -208,7 +207,7 @@ aggr_port_create(aggr_grp_t *grp, const datalink_id_t linkid, boolean_t force, if ((err = mac_unicast_add(mch, NULL, MAC_UNICAST_PRIMARY | MAC_UNICAST_DISABLE_TX_VID_CHECK, &mah, 0, &diag)) != 0) { - VERIFY(mac_margin_remove(mh, margin) == 0); + VERIFY3S(mac_margin_remove(mh, margin), ==, 0); id_free(aggr_portids, portid); goto fail; } @@ -263,6 +262,7 @@ aggr_port_create(aggr_grp_t *grp, const datalink_id_t linkid, boolean_t force, fail: if (mch != NULL) mac_client_close(mch, MAC_CLOSE_FLAGS_EXCLUSIVE); + mac_close(mh); return (err); } @@ -272,13 +272,11 @@ aggr_port_delete(aggr_port_t *port) { aggr_lacp_port_t *pl = &port->lp_lacp; - ASSERT(port->lp_mphp == NULL); ASSERT(!port->lp_promisc_on); - port->lp_closing = B_TRUE; + VERIFY0(mac_margin_remove(port->lp_mh, port->lp_margin)); + mac_client_clear_flow_cb(port->lp_mch); - VERIFY(mac_margin_remove(port->lp_mh, port->lp_margin) == 0); - mac_rx_clear(port->lp_mch); /* * If the notification callback is already in process and waiting for * the aggr grp's mac perimeter, don't wait (otherwise there would be @@ -309,8 +307,10 @@ aggr_port_delete(aggr_port_t *port) * port's MAC_NOTE_UNICST notify callback function being called. */ (void) mac_unicast_primary_set(port->lp_mh, port->lp_addr); + if (port->lp_mah != NULL) (void) mac_unicast_remove(port->lp_mch, port->lp_mah); + mac_client_close(port->lp_mch, MAC_CLOSE_FLAGS_EXCLUSIVE); mac_close(port->lp_mh); AGGR_PORT_REFRELE(port); @@ -521,6 +521,10 @@ aggr_port_stop(aggr_port_t *port) port->lp_started = B_FALSE; } +/* + * Set the promisc mode of the port. If the port is already in the + * requested mode then do nothing. + */ int aggr_port_promisc(aggr_port_t *port, boolean_t on) { @@ -529,34 +533,14 @@ aggr_port_promisc(aggr_port_t *port, boolean_t on) ASSERT(MAC_PERIM_HELD(port->lp_mh)); if (on == port->lp_promisc_on) - /* already in desired promiscous mode */ return (0); - if (on) { - mac_rx_clear(port->lp_mch); + rc = mac_set_promisc(port->lp_mh, on); - /* - * We use the promisc callback because without hardware - * rings, we deliver through flows that will cause duplicate - * delivery of packets when we've flipped into this mode - * to compensate for the lack of hardware MAC matching - */ - rc = mac_promisc_add(port->lp_mch, MAC_CLIENT_PROMISC_ALL, - aggr_recv_promisc_cb, port, &port->lp_mphp, - MAC_PROMISC_FLAGS_NO_TX_LOOP); - if (rc != 0) { - mac_rx_set(port->lp_mch, aggr_recv_cb, port); - return (rc); - } - } else { - mac_promisc_remove(port->lp_mphp); - port->lp_mphp = NULL; - mac_rx_set(port->lp_mch, aggr_recv_cb, port); - } - - port->lp_promisc_on = on; + if (rc == 0) + port->lp_promisc_on = on; - return (0); + return (rc); } /* @@ -596,35 +580,45 @@ aggr_port_stat(aggr_port_t *port, uint_t stat) } /* - * Add a non-primary unicast address to the underlying port. If the port - * supports HW Rx group, try to add the address into the HW Rx group of - * the port first. If that fails, or if the port does not support HW Rx - * group, enable the port's promiscous mode. + * Add a non-primary unicast address to the underlying port. If the + * port supports HW Rx groups, then try to add the address filter to + * the HW group first. If that fails, or if the port does not support + * RINGS capab, then enable the port's promiscous mode. */ int -aggr_port_addmac(aggr_port_t *port, const uint8_t *mac_addr) +aggr_port_addmac(aggr_port_t *port, uint_t idx, const uint8_t *mac_addr) { aggr_unicst_addr_t *addr, **pprev; mac_perim_handle_t pmph; int err; ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); + ASSERT3U(idx, <, MAX_GROUPS_PER_PORT); mac_perim_enter_by_mh(port->lp_mh, &pmph); /* - * If the underlying port support HW Rx group, add the mac to its - * RX group directly. + * If the port doesn't have a HW group to back the aggr's + * pseudo group, then try using the port's default group and + * let the aggr SW classify its traffic. This scenario happens + * when mixing ports with a different number of HW groups. */ - if ((port->lp_hwgh != NULL) && - ((mac_hwgroup_addmac(port->lp_hwgh, mac_addr)) == 0)) { + if (port->lp_hwghs[idx] == NULL) + idx = 0; + + /* + * If there is an underlying HW Rx group, then try adding this + * unicast address to it. + */ + if ((port->lp_hwghs[idx] != NULL) && + ((mac_hwgroup_addmac(port->lp_hwghs[idx], mac_addr)) == 0)) { mac_perim_exit(pmph); return (0); } /* - * If that fails, or if the port does not support HW Rx group, enable - * the port's promiscous mode. (Note that we turn on the promiscous - * mode only if the port is already started. + * If the port doesn't have HW groups, or we failed to add the + * HW filter, then enable the port's promiscuous mode. We + * enable promiscuous mode only if the port is already started. */ if (port->lp_started && ((err = aggr_port_promisc(port, B_TRUE)) != 0)) { @@ -656,13 +650,14 @@ aggr_port_addmac(aggr_port_t *port, const uint8_t *mac_addr) * promiscous mode. */ void -aggr_port_remmac(aggr_port_t *port, const uint8_t *mac_addr) +aggr_port_remmac(aggr_port_t *port, uint_t idx, const uint8_t *mac_addr) { aggr_grp_t *grp = port->lp_grp; aggr_unicst_addr_t *addr, **pprev; mac_perim_handle_t pmph; ASSERT(MAC_PERIM_HELD(grp->lg_mh)); + ASSERT3U(idx, <, MAX_GROUPS_PER_PORT); mac_perim_enter_by_mh(port->lp_mh, &pmph); /* @@ -675,6 +670,7 @@ aggr_port_remmac(aggr_port_t *port, const uint8_t *mac_addr) break; pprev = &addr->aua_next; } + if (addr != NULL) { /* * This unicast address put the port into the promiscous mode, @@ -687,52 +683,65 @@ aggr_port_remmac(aggr_port_t *port, const uint8_t *mac_addr) if (port->lp_prom_addr == NULL && !grp->lg_promisc) (void) aggr_port_promisc(port, B_FALSE); } else { - ASSERT(port->lp_hwgh != NULL); - (void) mac_hwgroup_remmac(port->lp_hwgh, mac_addr); + /* See comment in aggr_port_addmac(). */ + if (port->lp_hwghs[idx] == NULL) + idx = 0; + + ASSERT3P(port->lp_hwghs[idx], !=, NULL); + (void) mac_hwgroup_remmac(port->lp_hwghs[idx], mac_addr); } + mac_perim_exit(pmph); } int -aggr_port_addvlan(aggr_port_t *port, uint16_t vid) +aggr_port_addvlan(aggr_port_t *port, uint_t idx, uint16_t vid) { mac_perim_handle_t pmph; int err; ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); + ASSERT3U(idx, <, MAX_GROUPS_PER_PORT); mac_perim_enter_by_mh(port->lp_mh, &pmph); + /* See comment in aggr_port_addmac(). */ + if (port->lp_hwghs[idx] == NULL) + idx = 0; + /* * Add the VLAN filter to the HW group if the port has a HW * group. If the port doesn't have a HW group, then it will * implicitly allow tagged traffic to pass and there is * nothing to do. */ - if (port->lp_hwgh == NULL) { - mac_perim_exit(pmph); - return (0); - } + if (port->lp_hwghs[idx] == NULL) + err = 0; + else + err = mac_hwgroup_addvlan(port->lp_hwghs[idx], vid); - err = mac_hwgroup_addvlan(port->lp_hwgh, vid); mac_perim_exit(pmph); return (err); } int -aggr_port_remvlan(aggr_port_t *port, uint16_t vid) +aggr_port_remvlan(aggr_port_t *port, uint_t idx, uint16_t vid) { mac_perim_handle_t pmph; int err; ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh)); + ASSERT3U(idx, <, MAX_GROUPS_PER_PORT); mac_perim_enter_by_mh(port->lp_mh, &pmph); - if (port->lp_hwgh == NULL) { - mac_perim_exit(pmph); - return (0); - } + /* See comment in aggr_port_addmac(). */ + if (port->lp_hwghs[idx] == NULL) + idx = 0; + + if (port->lp_hwghs[idx] == NULL) + err = 0; + else + err = mac_hwgroup_remvlan(port->lp_hwghs[idx], vid); - err = mac_hwgroup_remvlan(port->lp_hwgh, vid); mac_perim_exit(pmph); return (err); } diff --git a/usr/src/uts/common/io/aggr/aggr_recv.c b/usr/src/uts/common/io/aggr/aggr_recv.c index 33a060da48..b6b3e6de1f 100644 --- a/usr/src/uts/common/io/aggr/aggr_recv.c +++ b/usr/src/uts/common/io/aggr/aggr_recv.c @@ -22,6 +22,7 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 OmniTI Computer Consulting, Inc All rights reserved. + * Copyright 2018 Joyent, Inc. */ /* @@ -56,7 +57,7 @@ aggr_recv_lacp(aggr_port_t *port, mac_resource_handle_t mrh, mblk_t *mp) { aggr_grp_t *grp = port->lp_grp; - /* in promiscuous mode, send copy of packet up */ + /* In promiscuous mode, pass copy of packet up. */ if (grp->lg_promisc) { mblk_t *nmp = copymsg(mp); @@ -74,23 +75,11 @@ aggr_recv_lacp(aggr_port_t *port, mac_resource_handle_t mrh, mblk_t *mp) /* ARGSUSED */ static void aggr_recv_path_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, - boolean_t loopback, boolean_t promisc_path) + boolean_t loopback) { aggr_port_t *port = (aggr_port_t *)arg; aggr_grp_t *grp = port->lp_grp; - /* - * In the case where lp_promisc_on has been turned on to - * compensate for insufficient hardware MAC matching and - * hardware rings are not in use we will fall back to - * using flows for delivery which can result in duplicates - * pushed up the stack. Only respect the chosen path. - */ - if (port->lp_promisc_on != promisc_path) { - freemsgchain(mp); - return; - } - if (grp->lg_lacp_mode == AGGR_LACP_OFF) { aggr_mac_rx(grp->lg_mh, mrh, mp); } else { @@ -175,18 +164,9 @@ aggr_recv_path_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, } } -/* ARGSUSED */ void aggr_recv_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t loopback) { - aggr_recv_path_cb(arg, mrh, mp, loopback, B_FALSE); -} - -/* ARGSUSED */ -void -aggr_recv_promisc_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, - boolean_t loopback) -{ - aggr_recv_path_cb(arg, mrh, mp, loopback, B_TRUE); + aggr_recv_path_cb(arg, mrh, mp, loopback); } diff --git a/usr/src/uts/common/io/mac/mac.c b/usr/src/uts/common/io/mac/mac.c index 4d450a539b..79a518a164 100644 --- a/usr/src/uts/common/io/mac/mac.c +++ b/usr/src/uts/common/io/mac/mac.c @@ -1457,7 +1457,7 @@ mac_rx_group_unmark(mac_group_t *grp, uint_t flag) * used by the aggr driver to access and control the underlying HW Rx group * and rings. In this case, the aggr driver has exclusive control of the * underlying HW Rx group/rings, it calls the following functions to - * start/stop the HW Rx rings, disable/enable polling, add/remove mac' + * start/stop the HW Rx rings, disable/enable polling, add/remove MAC * addresses, or set up the Rx callback. */ /* ARGSUSED */ @@ -1502,8 +1502,9 @@ mac_hwrings_get(mac_client_handle_t mch, mac_group_handle_t *hwgh, ASSERT(B_FALSE); return (-1); } + /* - * The mac client did not reserve any RX group, return directly. + * The MAC client did not reserve an Rx group, return directly. * This is probably because the underlying MAC does not support * any groups. */ @@ -1512,7 +1513,7 @@ mac_hwrings_get(mac_client_handle_t mch, mac_group_handle_t *hwgh, if (grp == NULL) return (0); /* - * This group must be reserved by this mac client. + * This group must be reserved by this MAC client. */ ASSERT((grp->mrg_state == MAC_GROUP_STATE_RESERVED) && (mcip == MAC_GROUP_ONLY_CLIENT(grp))); @@ -1527,6 +1528,78 @@ mac_hwrings_get(mac_client_handle_t mch, mac_group_handle_t *hwgh, return (cnt); } +/* + * Get the HW ring handles of the given group index. If the MAC + * doesn't have a group at this index, or any groups at all, then 0 is + * returned and hwgh is set to NULL. This is a private client API. The + * MAC perimeter must be held when calling this function. + * + * mh: A handle to the MAC that owns the group. + * + * idx: The index of the HW group to be read. + * + * hwgh: If non-NULL, contains a handle to the HW group on return. + * + * hwrh: An array of ring handles pointing to the HW rings in the + * group. The array must be large enough to hold a handle to each ring + * in the group. To be safe, this array should be of size MAX_RINGS_PER_GROUP. + * + * rtype: Used to determine if we are fetching Rx or Tx rings. + * + * Returns the number of rings in the group. + */ +uint_t +mac_hwrings_idx_get(mac_handle_t mh, uint_t idx, mac_group_handle_t *hwgh, + mac_ring_handle_t *hwrh, mac_ring_type_t rtype) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + mac_group_t *grp; + mac_ring_t *ring; + uint_t cnt = 0; + + /* + * The MAC perimeter must be held when accessing the + * mi_{rx,tx}_groups fields. + */ + ASSERT(MAC_PERIM_HELD(mh)); + ASSERT(rtype == MAC_RING_TYPE_RX || rtype == MAC_RING_TYPE_TX); + + if (rtype == MAC_RING_TYPE_RX) { + grp = mip->mi_rx_groups; + } else { + ASSERT(rtype == MAC_RING_TYPE_TX); + grp = mip->mi_tx_groups; + } + + while (grp != NULL && grp->mrg_index != idx) + grp = grp->mrg_next; + + /* + * If the MAC doesn't have a group at this index or doesn't + * impelement RINGS capab, then set hwgh to NULL and return 0. + */ + if (hwgh != NULL) + *hwgh = NULL; + + if (grp == NULL) + return (0); + + ASSERT3U(idx, ==, grp->mrg_index); + + for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next, cnt++) { + ASSERT3U(cnt, <, MAX_RINGS_PER_GROUP); + hwrh[cnt] = (mac_ring_handle_t)ring; + } + + /* A group should always have at least one ring. */ + ASSERT3U(cnt, >, 0); + + if (hwgh != NULL) + *hwgh = (mac_group_handle_t)grp; + + return (cnt); +} + /* * This function is called to get info about Tx/Rx rings. * @@ -1542,6 +1615,69 @@ mac_hwring_getinfo(mac_ring_handle_t rh) return (info->mri_flags); } +/* + * Set the passthru callback on the hardware ring. + */ +void +mac_hwring_set_passthru(mac_ring_handle_t hwrh, mac_rx_t fn, void *arg1, + mac_resource_handle_t arg2) +{ + mac_ring_t *hwring = (mac_ring_t *)hwrh; + + ASSERT3S(hwring->mr_type, ==, MAC_RING_TYPE_RX); + + hwring->mr_classify_type = MAC_PASSTHRU_CLASSIFIER; + + hwring->mr_pt_fn = fn; + hwring->mr_pt_arg1 = arg1; + hwring->mr_pt_arg2 = arg2; +} + +/* + * Clear the passthru callback on the hardware ring. + */ +void +mac_hwring_clear_passthru(mac_ring_handle_t hwrh) +{ + mac_ring_t *hwring = (mac_ring_t *)hwrh; + + ASSERT3S(hwring->mr_type, ==, MAC_RING_TYPE_RX); + + hwring->mr_classify_type = MAC_NO_CLASSIFIER; + + hwring->mr_pt_fn = NULL; + hwring->mr_pt_arg1 = NULL; + hwring->mr_pt_arg2 = NULL; +} + +void +mac_client_set_flow_cb(mac_client_handle_t mch, mac_rx_t func, void *arg1) +{ + mac_client_impl_t *mcip = (mac_client_impl_t *)mch; + flow_entry_t *flent = mcip->mci_flent; + + mutex_enter(&flent->fe_lock); + flent->fe_cb_fn = (flow_fn_t)func; + flent->fe_cb_arg1 = arg1; + flent->fe_cb_arg2 = NULL; + flent->fe_flags &= ~FE_MC_NO_DATAPATH; + mutex_exit(&flent->fe_lock); +} + +void +mac_client_clear_flow_cb(mac_client_handle_t mch) +{ + mac_client_impl_t *mcip = (mac_client_impl_t *)mch; + flow_entry_t *flent = mcip->mci_flent; + + mutex_enter(&flent->fe_lock); + flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop; + flent->fe_cb_arg1 = NULL; + flent->fe_cb_arg2 = NULL; + flent->fe_flags |= FE_MC_NO_DATAPATH; + mutex_exit(&flent->fe_lock); +} + /* * Export ddi interrupt handles from the HW ring to the pseudo ring and * setup the RX callback of the mac client which exclusively controls @@ -1614,8 +1750,44 @@ mac_hwring_enable_intr(mac_ring_handle_t rh) return (intr->mi_enable(intr->mi_handle)); } +/* + * Start the HW ring pointed to by rh. + * + * This is used by special MAC clients that are MAC themselves and + * need to exert control over the underlying HW rings of the NIC. + */ int mac_hwring_start(mac_ring_handle_t rh) +{ + mac_ring_t *rr_ring = (mac_ring_t *)rh; + int rv = 0; + + if (rr_ring->mr_state != MR_INUSE) + rv = mac_start_ring(rr_ring); + + return (rv); +} + +/* + * Stop the HW ring pointed to by rh. Also see mac_hwring_start(). + */ +void +mac_hwring_stop(mac_ring_handle_t rh) +{ + mac_ring_t *rr_ring = (mac_ring_t *)rh; + + if (rr_ring->mr_state != MR_FREE) + mac_stop_ring(rr_ring); +} + +/* + * Remove the quiesced flag from the HW ring pointed to by rh. + * + * This is used by special MAC clients that are MAC themselves and + * need to exert control over the underlying HW rings of the NIC. + */ +int +mac_hwring_activate(mac_ring_handle_t rh) { mac_ring_t *rr_ring = (mac_ring_t *)rh; @@ -1623,8 +1795,11 @@ mac_hwring_start(mac_ring_handle_t rh) return (0); } +/* + * Quiesce the HW ring pointed to by rh. Also see mac_hwring_activate(). + */ void -mac_hwring_stop(mac_ring_handle_t rh) +mac_hwring_quiesce(mac_ring_handle_t rh) { mac_ring_t *rr_ring = (mac_ring_t *)rh; @@ -1771,6 +1946,27 @@ mac_has_hw_vlan(mac_handle_t mh) return (MAC_GROUP_HW_VLAN(mip->mi_rx_groups)); } +/* + * Get the number of Rx HW groups on this MAC. + */ +uint_t +mac_get_num_rx_groups(mac_handle_t mh) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + + ASSERT(MAC_PERIM_HELD(mh)); + return (mip->mi_rx_group_count); +} + +int +mac_set_promisc(mac_handle_t mh, boolean_t value) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + + ASSERT(MAC_PERIM_HELD(mh)); + return (i_mac_promisc_set(mip, value)); +} + /* * Set the RX group to be shared/reserved. Note that the group must be * started/stopped outside of this function. @@ -2465,19 +2661,6 @@ mac_rx_classify(mac_impl_t *mip, mac_resource_handle_t mrh, mblk_t *mp) uint_t flags = FLOW_INBOUND; int err; - /* - * If the MAC is a port of an aggregation, pass FLOW_IGNORE_VLAN - * to mac_flow_lookup() so that the VLAN packets can be successfully - * passed to the non-VLAN aggregation flows. - * - * Note that there is possibly a race between this and - * mac_unicast_remove/add() and VLAN packets could be incorrectly - * classified to non-VLAN flows of non-aggregation MAC clients. These - * VLAN packets will be then filtered out by the MAC module. - */ - if ((mip->mi_state_flags & MIS_EXCLUSIVE) != 0) - flags |= FLOW_IGNORE_VLAN; - err = mac_flow_lookup(mip->mi_flow_tab, mp, flags, &flent); if (err != 0) { /* no registered receive function */ @@ -3811,9 +3994,27 @@ mac_start_group_and_rings(mac_group_t *group) for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next) { ASSERT(ring->mr_state == MR_FREE); + if ((rv = mac_start_ring(ring)) != 0) goto error; - ring->mr_classify_type = MAC_SW_CLASSIFIER; + + /* + * When aggr_set_port_sdu() is called, it will remove + * the port client's unicast address. This will cause + * MAC to stop the default group's rings on the port + * MAC. After it modifies the SDU, it will then re-add + * the unicast address. At which time, this function is + * called to start the default group's rings. Normally + * this function would set the classify type to + * MAC_SW_CLASSIFIER; but that will break aggr which + * relies on the passthru classify mode being set for + * correct delivery (see mac_rx_common()). To avoid + * that, we check for a passthru callback and set the + * classify type to MAC_PASSTHRU_CLASSIFIER; as it was + * before the rings were stopped. + */ + ring->mr_classify_type = (ring->mr_pt_fn != NULL) ? + MAC_PASSTHRU_CLASSIFIER : MAC_SW_CLASSIFIER; } return (0); diff --git a/usr/src/uts/common/io/mac/mac_client.c b/usr/src/uts/common/io/mac/mac_client.c index b918bf4aca..c39e3fa12f 100644 --- a/usr/src/uts/common/io/mac/mac_client.c +++ b/usr/src/uts/common/io/mac/mac_client.c @@ -1436,6 +1436,7 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name, mcip->mci_flent = flent; FLOW_MARK(flent, FE_MC_NO_DATAPATH); flent->fe_mcip = mcip; + /* * Place initial creation reference on the flow. This reference * is released in the corresponding delete action viz. @@ -2437,7 +2438,17 @@ done_setup: if (flent->fe_rx_ring_group != NULL) mac_rx_group_unmark(flent->fe_rx_ring_group, MR_INCIPIENT); FLOW_UNMARK(flent, FE_INCIPIENT); - FLOW_UNMARK(flent, FE_MC_NO_DATAPATH); + + /* + * If this is an aggr port client, don't enable the flow's + * datapath at this stage. Otherwise, bcast traffic could + * arrive while the aggr port is in the process of + * initializing. Instead, the flow's datapath is started later + * when mac_client_set_flow_cb() is called. + */ + if ((mcip->mci_state_flags & MCIS_IS_AGGR_PORT) == 0) + FLOW_UNMARK(flent, FE_MC_NO_DATAPATH); + mac_tx_client_unblock(mcip); return (0); bail: diff --git a/usr/src/uts/common/io/mac/mac_datapath_setup.c b/usr/src/uts/common/io/mac/mac_datapath_setup.c index a3fc2529b9..e3b660c3b3 100644 --- a/usr/src/uts/common/io/mac/mac_datapath_setup.c +++ b/usr/src/uts/common/io/mac/mac_datapath_setup.c @@ -1975,8 +1975,6 @@ no_softrings: } /* - * mac_fanout_setup: - * * Calls mac_srs_fanout_init() or modify() depending upon whether * the SRS is getting initialized or re-initialized. */ @@ -1989,14 +1987,14 @@ mac_fanout_setup(mac_client_impl_t *mcip, flow_entry_t *flent, int i, rx_srs_cnt; ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); + /* - * This is an aggregation port. Fanout will be setup - * over the aggregation itself. + * Aggr ports do not have SRSes. This function should never be + * called on an aggr port. */ - if (mcip->mci_state_flags & MCIS_EXCLUSIVE) - return; - + ASSERT3U((mcip->mci_state_flags & MCIS_IS_AGGR_PORT), ==, 0); mac_rx_srs = flent->fe_rx_srs[0]; + /* * Set up the fanout on the tx side only once, with the * first rx SRS. The CPU binding, fanout, and bandwidth @@ -2052,8 +2050,6 @@ mac_fanout_setup(mac_client_impl_t *mcip, flow_entry_t *flent, } /* - * mac_srs_create: - * * Create a mac_soft_ring_set_t (SRS). If soft_ring_fanout_type is * SRST_TX, an SRS for Tx side is created. Otherwise an SRS for Rx side * processing is created. @@ -2355,6 +2351,10 @@ mac_srs_group_setup(mac_client_impl_t *mcip, flow_entry_t *flent, mac_rx_srs_group_setup(mcip, flent, link_type); mac_tx_srs_group_setup(mcip, flent, link_type); + /* Aggr ports don't have SRSes; thus there is no soft ring fanout. */ + if ((mcip->mci_state_flags & MCIS_IS_AGGR_PORT) != 0) + return; + pool_lock(); cpupart = mac_pset_find(mrp, &use_default); mac_fanout_setup(mcip, flent, MCIP_RESOURCE_PROPS(mcip), @@ -2381,6 +2381,29 @@ mac_rx_srs_group_setup(mac_client_impl_t *mcip, flow_entry_t *flent, mac_group_t *rx_group = flent->fe_rx_ring_group; boolean_t no_unicast; + /* + * If this is an an aggr port, then don't setup Rx SRS and Rx + * soft rings as they won't be used. However, we still need to + * start the rings to receive data on them. + */ + if (mcip->mci_state_flags & MCIS_IS_AGGR_PORT) { + if (rx_group == NULL) + return; + + for (ring = rx_group->mrg_rings; ring != NULL; + ring = ring->mr_next) { + if (ring->mr_state != MR_INUSE) + (void) mac_start_ring(ring); + } + + return; + } + + /* + * Aggr ports should never have SRSes. + */ + ASSERT3U((mcip->mci_state_flags & MCIS_IS_AGGR_PORT), ==, 0); + fanout_type = mac_find_fanout(flent, link_type); no_unicast = (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) != 0; @@ -2469,38 +2492,40 @@ void mac_tx_srs_group_setup(mac_client_impl_t *mcip, flow_entry_t *flent, uint32_t link_type) { - int cnt; - int ringcnt; - mac_ring_t *ring; - mac_group_t *grp; - /* - * If we are opened exclusively (like aggr does for aggr_ports), - * don't set up Tx SRS and Tx soft rings as they won't be used. - * The same thing has to be done for Rx side also. See bug: - * 6880080 + * If this is an exclusive client (e.g. an aggr port), then + * don't setup Tx SRS and Tx soft rings as they won't be used. + * However, we still need to start the rings to send data + * across them. */ if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { - /* - * If we have rings, start them here. - */ - if (flent->fe_tx_ring_group == NULL) - return; + mac_ring_t *ring; + mac_group_t *grp; + grp = (mac_group_t *)flent->fe_tx_ring_group; - ringcnt = grp->mrg_cur_count; - ring = grp->mrg_rings; - for (cnt = 0; cnt < ringcnt; cnt++) { - if (ring->mr_state != MR_INUSE) { + + if (grp == NULL) + return; + + for (ring = grp->mrg_rings; ring != NULL; + ring = ring->mr_next) { + if (ring->mr_state != MR_INUSE) (void) mac_start_ring(ring); - } - ring = ring->mr_next; } + return; } + + /* + * Aggr ports should never have SRSes. + */ + ASSERT3U((mcip->mci_state_flags & MCIS_IS_AGGR_PORT), ==, 0); + if (flent->fe_tx_srs == NULL) { (void) mac_srs_create(mcip, flent, SRST_TX | link_type, NULL, mcip, NULL, NULL); } + mac_tx_srs_setup(mcip, flent); } @@ -3168,12 +3193,12 @@ mac_datapath_teardown(mac_client_impl_t *mcip, flow_entry_t *flent, mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE); mac_flow_wait(flent, FLOW_DRIVER_UPCALL); - /* Now quiesce and destroy all SRS and soft rings */ + /* Quiesce and destroy all the SRSes. */ mac_rx_srs_group_teardown(flent, B_FALSE); mac_tx_srs_group_teardown(mcip, flent, SRST_LINK); - ASSERT((mcip->mci_flent == flent) && - (flent->fe_next == NULL)); + ASSERT3P(mcip->mci_flent, ==, flent); + ASSERT3P(flent->fe_next, ==, NULL); /* * Release our hold on the group as well. We need @@ -4022,8 +4047,8 @@ mac_fanout_recompute_client(mac_client_impl_t *mcip, cpupart_t *cpupart) } /* - * Walk through the list of mac clients for the MAC. - * For each active mac client, recompute the number of soft rings + * Walk through the list of MAC clients for the MAC. + * For each active MAC client, recompute the number of soft rings * associated with every client, only if current speed is different * from the speed that was previously used for soft ring computation. * If the cable is disconnected whlie the NIC is started, we would get @@ -4046,6 +4071,10 @@ mac_fanout_recompute(mac_impl_t *mip) for (mcip = mip->mi_clients_list; mcip != NULL; mcip = mcip->mci_client_next) { + /* Aggr port clients don't have SRSes. */ + if ((mcip->mci_state_flags & MCIS_IS_AGGR_PORT) != 0) + continue; + if ((mcip->mci_state_flags & MCIS_SHARE_BOUND) != 0 || !MCIP_DATAPATH_SETUP(mcip)) continue; @@ -4058,6 +4087,7 @@ mac_fanout_recompute(mac_impl_t *mip) mac_set_pool_effective(use_default, cpupart, mrp, emrp); pool_unlock(); } + i_mac_perim_exit(mip); } diff --git a/usr/src/uts/common/io/mac/mac_provider.c b/usr/src/uts/common/io/mac/mac_provider.c index 26f501668e..a3f0ca89ed 100644 --- a/usr/src/uts/common/io/mac/mac_provider.c +++ b/usr/src/uts/common/io/mac/mac_provider.c @@ -699,7 +699,6 @@ mac_rx_common(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain) mac_ring_t *mr = (mac_ring_t *)mrh; mac_soft_ring_set_t *mac_srs; mblk_t *bp = mp_chain; - boolean_t hw_classified = B_FALSE; /* * If there are any promiscuous mode callbacks defined for @@ -711,7 +710,7 @@ mac_rx_common(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain) if (mr != NULL) { /* * If the SRS teardown has started, just return. The 'mr' - * continues to be valid until the driver unregisters the mac. + * continues to be valid until the driver unregisters the MAC. * Hardware classified packets will not make their way up * beyond this point once the teardown has started. The driver * is never passed a pointer to a flow entry or SRS or any @@ -724,11 +723,25 @@ mac_rx_common(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain) freemsgchain(mp_chain); return; } - if (mr->mr_classify_type == MAC_HW_CLASSIFIER) { - hw_classified = B_TRUE; + + /* + * The ring is in passthru mode; pass the chain up to + * the pseudo ring. + */ + if (mr->mr_classify_type == MAC_PASSTHRU_CLASSIFIER) { MR_REFHOLD_LOCKED(mr); + mutex_exit(&mr->mr_lock); + mr->mr_pt_fn(mr->mr_pt_arg1, mr->mr_pt_arg2, mp_chain, + B_FALSE); + MR_REFRELE(mr); + return; } - mutex_exit(&mr->mr_lock); + + /* + * The passthru callback should only be set when in + * MAC_PASSTHRU_CLASSIFIER mode. + */ + ASSERT3P(mr->mr_pt_fn, ==, NULL); /* * We check if an SRS is controlling this ring. @@ -736,19 +749,24 @@ mac_rx_common(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain) * routine otherwise we need to go through mac_rx_classify * to reach the right place. */ - if (hw_classified) { + if (mr->mr_classify_type == MAC_HW_CLASSIFIER) { + MR_REFHOLD_LOCKED(mr); + mutex_exit(&mr->mr_lock); + ASSERT3P(mr->mr_srs, !=, NULL); mac_srs = mr->mr_srs; + /* - * This is supposed to be the fast path. - * All packets received though here were steered by - * the hardware classifier, and share the same - * MAC header info. + * This is the fast path. All packets received + * on this ring are hardware classified and + * share the same MAC header info. */ mac_srs->srs_rx.sr_lower_proc(mh, (mac_resource_handle_t)mac_srs, mp_chain, B_FALSE); MR_REFRELE(mr); return; } + + mutex_exit(&mr->mr_lock); /* We'll fall through to software classification */ } else { flow_entry_t *flent; diff --git a/usr/src/uts/common/io/mac/mac_stat.c b/usr/src/uts/common/io/mac/mac_stat.c index 31972f94d8..dbb5c0a914 100644 --- a/usr/src/uts/common/io/mac/mac_stat.c +++ b/usr/src/uts/common/io/mac/mac_stat.c @@ -21,6 +21,7 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2018 Joyent, Inc. */ /* @@ -261,7 +262,7 @@ static stat_info_t rx_srs_stats_list[] = { {RX_SRS_STAT_OFF(mrs_chaincntover50)}, {RX_SRS_STAT_OFF(mrs_ierrors)} }; -#define RX_SRS_STAT_SIZE \ +#define RX_SRS_STAT_SIZE \ (sizeof (rx_srs_stats_list) / sizeof (stat_info_t)) #define TX_SOFTRING_STAT_OFF(f) (offsetof(mac_tx_stats_t, f)) @@ -273,14 +274,14 @@ static stat_info_t tx_softring_stats_list[] = { {TX_SOFTRING_STAT_OFF(mts_unblockcnt)}, {TX_SOFTRING_STAT_OFF(mts_sdrops)}, }; -#define TX_SOFTRING_STAT_SIZE \ +#define TX_SOFTRING_STAT_SIZE \ (sizeof (tx_softring_stats_list) / sizeof (stat_info_t)) static void i_mac_add_stats(void *sum, void *op1, void *op2, stat_info_t stats_list[], uint_t size) { - int i; + int i; for (i = 0; i < size; i++) { uint64_t *op1_val = (uint64_t *) @@ -678,8 +679,8 @@ i_mac_rx_hwlane_stat_create(mac_soft_ring_set_t *mac_srs, const char *modname, static uint64_t i_mac_misc_stat_get(void *handle, uint_t stat) { - flow_entry_t *flent = handle; - mac_client_impl_t *mcip = flent->fe_mcip; + flow_entry_t *flent = handle; + mac_client_impl_t *mcip = flent->fe_mcip; mac_misc_stats_t *mac_misc_stat = &mcip->mci_misc_stat; mac_rx_stats_t *mac_rx_stat; mac_tx_stats_t *mac_tx_stat; @@ -870,9 +871,9 @@ i_mac_tx_hwlane_stat_create(mac_soft_ring_t *ringp, const char *modname, static uint64_t i_mac_rx_fanout_stat_get(void *handle, uint_t stat) { - mac_soft_ring_t *tcp_ringp = (mac_soft_ring_t *)handle; + mac_soft_ring_t *tcp_ringp = (mac_soft_ring_t *)handle; mac_soft_ring_t *udp_ringp = NULL, *oth_ringp = NULL; - mac_soft_ring_set_t *mac_srs = tcp_ringp->s_ring_set; + mac_soft_ring_set_t *mac_srs = tcp_ringp->s_ring_set; int index; uint64_t val; @@ -1003,6 +1004,7 @@ void mac_ring_stat_create(mac_ring_t *ring) { mac_impl_t *mip = ring->mr_mip; + mac_group_t *grp = (mac_group_t *)ring->mr_gh; char statname[MAXNAMELEN]; char modname[MAXNAMELEN]; @@ -1014,8 +1016,8 @@ mac_ring_stat_create(mac_ring_t *ring) switch (ring->mr_type) { case MAC_RING_TYPE_RX: - (void) snprintf(statname, sizeof (statname), "mac_rx_ring%d", - ring->mr_index); + (void) snprintf(statname, sizeof (statname), + "mac_rx_ring_%d_%d", grp->mrg_index, ring->mr_index); i_mac_rx_ring_stat_create(ring, modname, statname); break; @@ -1035,7 +1037,7 @@ void mac_srs_stat_create(mac_soft_ring_set_t *mac_srs) { flow_entry_t *flent = mac_srs->srs_flent; - char statname[MAXNAMELEN]; + char statname[MAXNAMELEN]; boolean_t is_tx_srs; /* No hardware/software lanes for user defined flows */ diff --git a/usr/src/uts/common/sys/aggr_impl.h b/usr/src/uts/common/sys/aggr_impl.h index 415e176ef3..80733aa31e 100644 --- a/usr/src/uts/common/sys/aggr_impl.h +++ b/usr/src/uts/common/sys/aggr_impl.h @@ -56,6 +56,8 @@ extern "C" { */ #define MAC_PSEUDO_RING_INUSE 0x01 +#define MAX_GROUPS_PER_PORT 128 + /* * VLAN filters placed on the Rx pseudo group. */ @@ -71,14 +73,23 @@ typedef struct aggr_unicst_addr_s { } aggr_unicst_addr_t; typedef struct aggr_pseudo_rx_ring_s { - mac_ring_handle_t arr_rh; /* filled in by aggr_fill_ring() */ - struct aggr_port_s *arr_port; - mac_ring_handle_t arr_hw_rh; - uint_t arr_flags; - uint64_t arr_gen; + mac_ring_handle_t arr_rh; /* set by aggr_fill_ring() */ + struct aggr_port_s *arr_port; + struct aggr_pseudo_rx_group_s *arr_grp; + mac_ring_handle_t arr_hw_rh; + uint_t arr_flags; + uint64_t arr_gen; } aggr_pseudo_rx_ring_t; +/* + * An aggr pseudo group abstracts the underlying ports' HW groups. For + * example, if each port has 8 groups (mac_group_t), then the aggr + * will create 8 pseudo groups. Each pseudo group represents a + * collection of HW groups: one group from each port. If you have + * three ports then the pseudo group stands in for three HW groups. + */ typedef struct aggr_pseudo_rx_group_s { + uint_t arg_index; struct aggr_grp_s *arg_grp; /* filled in by aggr_fill_group() */ mac_group_handle_t arg_gh; /* filled in by aggr_fill_group() */ aggr_unicst_addr_t *arg_macaddr; @@ -119,12 +130,13 @@ typedef struct aggr_port_s { lp_collector_enabled : 1, lp_promisc_on : 1, lp_no_link_update : 1, - lp_rx_grp_added : 1, lp_tx_grp_added : 1, lp_closing : 1, - lp_pad_bits : 24; + lp_pad_bits : 25; mac_handle_t lp_mh; - mac_client_handle_t lp_mch; + + mac_client_handle_t lp_mch; + const mac_info_t *lp_mip; mac_notify_handle_t lp_mnh; uint_t lp_tx_idx; /* idx in group's tx array */ @@ -136,13 +148,19 @@ typedef struct aggr_port_s { aggr_lacp_port_t lp_lacp; /* LACP state */ lacp_stats_t lp_lacp_stats; uint32_t lp_margin; - mac_promisc_handle_t lp_mphp; + mac_unicast_handle_t lp_mah; /* List of non-primary addresses that requires promiscous mode set */ aggr_unicst_addr_t *lp_prom_addr; - /* handle of the underlying HW RX group */ - mac_group_handle_t lp_hwgh; + + /* + * References to the underlying HW Rx groups of this port. + * Used by aggr to program HW classification for the pseudo + * groups. + */ + mac_group_handle_t lp_hwghs[MAX_GROUPS_PER_PORT]; + int lp_tx_ring_cnt; /* handles of the underlying HW TX rings */ mac_ring_handle_t *lp_tx_rings; @@ -189,7 +207,7 @@ typedef struct aggr_grp_s { lg_lso : 1, lg_pad_bits : 8; aggr_port_t *lg_ports; /* list of configured ports */ - aggr_port_t *lg_mac_addr_port; + aggr_port_t *lg_mac_addr_port; /* using address of this port */ mac_handle_t lg_mh; zoneid_t lg_zoneid; uint_t lg_nattached_ports; @@ -233,7 +251,9 @@ typedef struct aggr_grp_s { kthread_t *lg_lacp_rx_thread; boolean_t lg_lacp_done; - aggr_pseudo_rx_group_t lg_rx_group; + uint_t lg_rx_group_count; + aggr_pseudo_rx_group_t lg_rx_groups[MAX_GROUPS_PER_PORT]; + aggr_pseudo_tx_group_t lg_tx_group; kmutex_t lg_tx_flowctl_lock; @@ -328,8 +348,6 @@ extern boolean_t aggr_port_notify_link(aggr_grp_t *, aggr_port_t *); extern void aggr_port_init_callbacks(aggr_port_t *); extern void aggr_recv_cb(void *, mac_resource_handle_t, mblk_t *, boolean_t); -extern void aggr_recv_promisc_cb(void *, mac_resource_handle_t, mblk_t *, - boolean_t); extern void aggr_tx_ring_update(void *, uintptr_t); extern void aggr_tx_notify_thread(void *); @@ -357,11 +375,11 @@ extern void aggr_grp_port_hold(aggr_port_t *); extern void aggr_grp_port_rele(aggr_port_t *); extern void aggr_grp_port_wait(aggr_grp_t *); -extern int aggr_port_addmac(aggr_port_t *, const uint8_t *); -extern void aggr_port_remmac(aggr_port_t *, const uint8_t *); +extern int aggr_port_addmac(aggr_port_t *, uint_t, const uint8_t *); +extern void aggr_port_remmac(aggr_port_t *, uint_t, const uint8_t *); -extern int aggr_port_addvlan(aggr_port_t *, uint16_t); -extern int aggr_port_remvlan(aggr_port_t *, uint16_t); +extern int aggr_port_addvlan(aggr_port_t *, uint_t, uint16_t); +extern int aggr_port_remvlan(aggr_port_t *, uint_t, uint16_t); extern mblk_t *aggr_ring_tx(void *, mblk_t *); extern mblk_t *aggr_find_tx_ring(void *, mblk_t *, diff --git a/usr/src/uts/common/sys/mac_client_priv.h b/usr/src/uts/common/sys/mac_client_priv.h index 77475b339e..965dca263c 100644 --- a/usr/src/uts/common/sys/mac_client_priv.h +++ b/usr/src/uts/common/sys/mac_client_priv.h @@ -121,9 +121,17 @@ extern void mac_tx_client_quiesce(mac_client_handle_t); extern void mac_tx_client_condemn(mac_client_handle_t); extern void mac_tx_client_restart(mac_client_handle_t); extern void mac_srs_perm_quiesce(mac_client_handle_t, boolean_t); +extern uint_t mac_hwrings_idx_get(mac_handle_t, uint_t, mac_group_handle_t *, + mac_ring_handle_t *, mac_ring_type_t); extern int mac_hwrings_get(mac_client_handle_t, mac_group_handle_t *, mac_ring_handle_t *, mac_ring_type_t); extern uint_t mac_hwring_getinfo(mac_ring_handle_t); +extern void mac_hwring_set_passthru(mac_ring_handle_t, mac_rx_t, void *, + mac_resource_handle_t); +extern void mac_hwring_clear_passthru(mac_ring_handle_t); +extern void mac_client_set_flow_cb(mac_client_handle_t, mac_rx_t, void *); +extern void mac_client_clear_flow_cb(mac_client_handle_t); + extern void mac_hwring_setup(mac_ring_handle_t, mac_resource_handle_t, mac_ring_handle_t); extern void mac_hwring_teardown(mac_ring_handle_t); @@ -131,6 +139,8 @@ extern int mac_hwring_disable_intr(mac_ring_handle_t); extern int mac_hwring_enable_intr(mac_ring_handle_t); extern int mac_hwring_start(mac_ring_handle_t); extern void mac_hwring_stop(mac_ring_handle_t); +extern int mac_hwring_activate(mac_ring_handle_t); +extern void mac_hwring_quiesce(mac_ring_handle_t); extern mblk_t *mac_hwring_poll(mac_ring_handle_t, int); extern mblk_t *mac_hwring_tx(mac_ring_handle_t, mblk_t *); extern int mac_hwring_getstat(mac_ring_handle_t, uint_t, uint64_t *); @@ -149,6 +159,9 @@ extern int mac_hwgroup_remvlan(mac_group_handle_t, uint16_t); extern boolean_t mac_has_hw_vlan(mac_handle_t); +extern uint_t mac_get_num_rx_groups(mac_handle_t); +extern int mac_set_promisc(mac_handle_t, boolean_t); + extern void mac_set_upper_mac(mac_client_handle_t, mac_handle_t, mac_resource_props_t *); diff --git a/usr/src/uts/common/sys/mac_impl.h b/usr/src/uts/common/sys/mac_impl.h index eebbde37de..df03a76715 100644 --- a/usr/src/uts/common/sys/mac_impl.h +++ b/usr/src/uts/common/sys/mac_impl.h @@ -208,9 +208,18 @@ struct mac_ring_s { mac_ring_t *mr_next; /* next ring in the chain */ mac_group_handle_t mr_gh; /* reference to group */ - mac_classify_type_t mr_classify_type; /* HW vs SW */ + mac_classify_type_t mr_classify_type; struct mac_soft_ring_set_s *mr_srs; /* associated SRS */ - mac_ring_handle_t mr_prh; /* associated pseudo ring hdl */ + mac_ring_handle_t mr_prh; /* associated pseudo ring hdl */ + + /* + * Ring passthru callback and arguments. See the + * MAC_PASSTHRU_CLASSIFIER comment in mac_provider.h. + */ + mac_rx_t mr_pt_fn; + void *mr_pt_arg1; + mac_resource_handle_t mr_pt_arg2; + uint_t mr_refcnt; /* Ring references */ /* ring generation no. to guard against drivers using stale rings */ uint64_t mr_gen_num; diff --git a/usr/src/uts/common/sys/mac_provider.h b/usr/src/uts/common/sys/mac_provider.h index 301bc9a058..8e00dfced6 100644 --- a/usr/src/uts/common/sys/mac_provider.h +++ b/usr/src/uts/common/sys/mac_provider.h @@ -242,16 +242,59 @@ typedef struct mac_callbacks_s { /* * Virtualization Capabilities */ + /* - * The ordering of entries below is important. MAC_HW_CLASSIFIER - * is the cutoff below which are entries which don't depend on - * H/W. MAC_HW_CLASSIFIER and entries after that are cases where - * H/W has been updated through add/modify/delete APIs. + * The type of ring classification. This is used by MAC to determine + * what, if any, processing it has to do upon receiving traffic on a + * particular Rx ring. + * + * MAC_NO_CLASSIFIER + * + * No classification has been set. No traffic should cross an Rx + * ring in this state. + * + * MAC_SW_CLASSIFIER + * + * The driver delivers traffic for multiple clients to this ring. + * All traffic must be software classified by MAC to guarantee + * delivery to the correct client. This classification type may + * be chosen for several reasons. + * + * o The driver provides only one group and there are multiple + * clients using the MAC. + * + * o The driver provides some hardware filtering but not enough + * to fully classify the traffic. E.g., a VLAN VNIC requires L2 + * unicast address filtering as well as VLAN filtering, but + * some drivers may only support the former. + * + * o The ring belongs to the default group. The default group + * acts as a spillover for all clients that can't reserve an + * exclusive group. It also handles multicast traffic for all + * clients. For these reasons, the default group's rings are + * always software classified. + * + * MAC_HW_CLASSIFIER + * + * The driver delivers traffic for a single MAC client across + * this ring. With this guarantee, MAC can simply pass the + * traffic up the stack or even allow polling of the ring. + * + * MAC_PASSTHRU_CLASSIFIER + * + * The ring is in "passthru" mode. In this mode we bypass all of + * the typical MAC processing and pass the traffic directly to + * the mr_pt_fn callback, see mac_rx_common(). This is used in + * cases where there is another module acting as MAC provider on + * behalf of the driver. E.g., link aggregations use this mode to + * take full control of the port's rings; allowing it to enforce + * LACP protocols and aggregate rings across discrete drivers. */ typedef enum { MAC_NO_CLASSIFIER = 0, MAC_SW_CLASSIFIER, - MAC_HW_CLASSIFIER + MAC_HW_CLASSIFIER, + MAC_PASSTHRU_CLASSIFIER } mac_classify_type_t; typedef void (*mac_rx_func_t)(void *, mac_resource_handle_t, mblk_t *, @@ -364,6 +407,7 @@ typedef struct mac_ring_info_s { mac_ring_poll_t poll; } mrfunion; mac_ring_stat_t mri_stat; + /* * mri_flags will have some bits set to indicate some special * property/feature of a ring like serialization needed for a diff --git a/usr/src/uts/sun4v/io/vnet.c b/usr/src/uts/sun4v/io/vnet.c index c9e378f89e..96fb04175d 100644 --- a/usr/src/uts/sun4v/io/vnet.c +++ b/usr/src/uts/sun4v/io/vnet.c @@ -22,6 +22,7 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2018 Joyent, Inc. */ #include @@ -1132,9 +1133,9 @@ vnet_mac_register(vnet_t *vnetp) static int vnet_read_mac_address(vnet_t *vnetp) { - uchar_t *macaddr; - uint32_t size; - int rv; + uchar_t *macaddr; + uint32_t size; + int rv; rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); @@ -2317,7 +2318,7 @@ vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index, */ static void vnet_get_group(void *arg, mac_ring_type_t type, const int index, - mac_group_info_t *infop, mac_group_handle_t handle) + mac_group_info_t *infop, mac_group_handle_t handle) { vnet_t *vnetp = (vnet_t *)arg; @@ -2405,7 +2406,7 @@ vnet_rx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num) return (0); } - err = mac_hwring_start(rx_ringp->hw_rh); + err = mac_hwring_activate(rx_ringp->hw_rh); if (err == 0) { rx_ringp->gen_num = mr_gen_num; rx_ringp->state |= VNET_RXRING_STARTED; @@ -2443,7 +2444,7 @@ vnet_rx_ring_stop(mac_ring_driver_t arg) return; } - mac_hwring_stop(rx_ringp->hw_rh); + mac_hwring_quiesce(rx_ringp->hw_rh); rx_ringp->state &= ~VNET_RXRING_STARTED; } @@ -2630,7 +2631,7 @@ vnet_rx_poll(void *arg, int bytes_to_pickup) /* ARGSUSED */ void vnet_hio_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, - boolean_t loopback) + boolean_t loopback) { vnet_t *vnetp = (vnet_t *)arg; vnet_pseudo_rx_ring_t *ringp = (vnet_pseudo_rx_ring_t *)mrh; @@ -2846,7 +2847,7 @@ vnet_bind_hwrings(vnet_t *vnetp) /* Start the hwring if needed */ if (rx_ringp->state & VNET_RXRING_STARTED) { - rv = mac_hwring_start(rx_ringp->hw_rh); + rv = mac_hwring_activate(rx_ringp->hw_rh); if (rv != 0) { mac_hwring_teardown(rx_ringp->hw_rh); rx_ringp->hw_rh = NULL; @@ -2920,7 +2921,7 @@ vnet_unbind_hwrings(vnet_t *vnetp) rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX]; if (rx_ringp->hw_rh != NULL) { /* Stop the hwring */ - mac_hwring_stop(rx_ringp->hw_rh); + mac_hwring_quiesce(rx_ringp->hw_rh); /* Teardown the hwring */ mac_hwring_teardown(rx_ringp->hw_rh); -- cgit v1.2.3 From 12eb87fbfbcd9e0abde89898daa0a87c695807e4 Mon Sep 17 00:00:00 2001 From: Alex Wilson Date: Wed, 8 Jan 2020 18:05:31 +1000 Subject: 12205 want generic NIC transceiver fault events Reviewed by: Robert Mustacchi Reviewed by: Paul Winder Reviewed by: Rob Johnston Approved by: Garrett D'Amore --- usr/src/cmd/fm/dicts/Makefile | 3 +- usr/src/cmd/fm/dicts/NIC.dict | 21 ++++ usr/src/cmd/fm/dicts/NIC.po | 98 ++++++++++++++++ usr/src/cmd/fm/eversholt/files/common/nic.esc | 127 +++++++++++++++++++++ usr/src/cmd/fm/eversholt/files/i386/Makefile | 3 +- usr/src/cmd/fm/eversholt/files/sparc/Makefile | 3 +- .../consolidation-osnet-osnet-message-files.mf | 1 + usr/src/pkg/manifests/service-fault-management.mf | 5 + usr/src/uts/common/sys/fm/io/ddi.h | 11 ++ 9 files changed, 269 insertions(+), 3 deletions(-) create mode 100644 usr/src/cmd/fm/dicts/NIC.dict create mode 100644 usr/src/cmd/fm/dicts/NIC.po create mode 100644 usr/src/cmd/fm/eversholt/files/common/nic.esc (limited to 'usr/src/uts/common/sys') diff --git a/usr/src/cmd/fm/dicts/Makefile b/usr/src/cmd/fm/dicts/Makefile index 22bebd3ae8..93e0303f83 100644 --- a/usr/src/cmd/fm/dicts/Makefile +++ b/usr/src/cmd/fm/dicts/Makefile @@ -38,7 +38,8 @@ common_DCNAMES = \ SCA1000 \ SENSOR \ STORAGE \ - TEST + TEST \ + NIC i386_DCNAMES = \ AMD \ diff --git a/usr/src/cmd/fm/dicts/NIC.dict b/usr/src/cmd/fm/dicts/NIC.dict new file mode 100644 index 0000000000..670dc53d46 --- /dev/null +++ b/usr/src/cmd/fm/dicts/NIC.dict @@ -0,0 +1,21 @@ +# +# Copyright 2020 the University of Queensland +# Use is subject to license terms. +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +FMDICT: name=NIC version=1 maxkey=4 + +fault.io.nic.transceiver.notsupp=0 +fault.io.nic.transceiver.whitelist=1 +fault.io.nic.transceiver.overtemp=2 +fault.io.nic.transceiver.hwfail=3 +fault.io.nic.transceiver.unknown=4 diff --git a/usr/src/cmd/fm/dicts/NIC.po b/usr/src/cmd/fm/dicts/NIC.po new file mode 100644 index 0000000000..46f1c859b9 --- /dev/null +++ b/usr/src/cmd/fm/dicts/NIC.po @@ -0,0 +1,98 @@ +# +# Copyright 2020 the University of Queensland +# Use is subject to license terms. +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# code: NIC-8000-0Q +# keys: fault.io.nic.transceiver.notsupp +# +msgid "NIC-8000-0Q.type" +msgstr "Fault" +msgid "NIC-8000-0Q.severity" +msgstr "Critical" +msgid "NIC-8000-0Q.description" +msgstr "NIC transceiver module % (SFP/SFP+/QSFP+ etc.) in % is of a type that is not supported. This may be due to an incompatible link type or speed. In some NICs, this may also be caused by enforcement of a vendor or part whitelist.\n\n NIC data link: % (%)\n Module vendor: %\n Module part: %\n Module serial: %\n\n Refer to %s for more information." +msgid "NIC-8000-0Q.response" +msgstr "The transceiver module has been disabled, and the network data link associated with it (%) has been marked as down.\n" +msgid "NIC-8000-0Q.impact" +msgstr "No network traffic will pass through the data link or network interfaces associated with this transceiver slot.\n" +msgid "NIC-8000-0Q.action" +msgstr "Replace the transceiver module with one of a supported type.\n" + +# +# code: NIC-8000-1C +# keys: fault.io.nic.transceiver.whitelist +# +msgid "NIC-8000-1C.type" +msgstr "Fault" +msgid "NIC-8000-1C.severity" +msgstr "Critical" +msgid "NIC-8000-1C.description" +msgstr "NIC transceiver module % (SFP/SFP+/QSFP+ etc.) in % is of a type that is not allowed to be used with this NIC (due to a hardware-enforced vendor or part whitelist).\n\n NIC data link: % (%)\n Module vendor: %\n Module part: %\n Module serial: %\n\n Refer to %s for more information." +msgid "NIC-8000-1C.response" +msgstr "The transceiver module has been disabled, and the network data link associated with it (%) has been marked as down.\n" +msgid "NIC-8000-1C.impact" +msgstr "No network traffic will pass through the data link or network\ninterfaces associated with this transceiver slot.\n" +msgid "NIC-8000-1C.action" +msgstr "Replace the transceiver module with one of a supported type.\n" + +# +# code: NIC-8000-2R +# keys: fault.io.nic.transceiver.overtemp +# +msgid "NIC-8000-2R.type" +msgstr "Fault" +msgid "NIC-8000-2R.severity" +msgstr "Critical" +msgid "NIC-8000-2R.description" +msgstr "NIC transceiver module % (SFP/SFP+/QSFP+ etc.) in % has overheated.\n\n NIC data link: % (%)\n Module vendor: %\n Module part: %\n Module serial: %\n\n Refer to %s for more information." +msgid "NIC-8000-2R.response" +msgstr "The transceiver module has been disabled, and the network data link associated with it (%) has been marked as down.\n" +msgid "NIC-8000-2R.impact" +msgstr "No network traffic will pass through the data link or network interfaces associated with this transceiver slot.\n" +msgid "NIC-8000-2R.action" +msgstr "Remove the transceiver module and check for adequate ventilation\nand cooling. Re-inserting the module after it has cooled will restore service.\n" + +# +# code: NIC-8000-34 +# keys: fault.io.nic.transceiver.hwfail +# +msgid "NIC-8000-34.type" +msgstr "Fault" +msgid "NIC-8000-34.severity" +msgstr "Critical" +msgid "NIC-8000-34.description" +msgstr "NIC transceiver module % (SFP/SFP+/QSFP+ etc.) in % has experienced a hardware failure.\n\n NIC data link: % (%)\n Module vendor: %\n Module part: %\n Module serial: %\n\n Refer to %s for more information." +msgid "NIC-8000-34.response" +msgstr "The transceiver module has been disabled, and the network data link associated with it (%) has been marked as down.\n" +msgid "NIC-8000-34.impact" +msgstr "No network traffic will pass through the data link or network\ninterfaces associated with this transceiver slot.\n" +msgid "NIC-8000-34.action" +msgstr "Remove and check the transceiver module, and consider replacing it.\n" + +# +# code: NIC-8000-4X +# keys: fault.io.nic.transceiver.unknown +# +msgid "NIC-8000-4X.type" +msgstr "Fault" +msgid "NIC-8000-4X.severity" +msgstr "Critical" +msgid "NIC-8000-4X.description" +msgstr "The slot for NIC transceiver module % (SFP/SFP+/QSFP+ etc.) in % is occupied, but hardware did not find a valid transceiver in it.\n Refer to %s for more information." +msgid "NIC-8000-4X.response" +msgstr "The transceiver module slot has been disabled, and the network data link associated with it (%) has been marked as down.\n" +msgid "NIC-8000-4X.impact" +msgstr "No network traffic will pass through the data link or network\ninterfaces associated with this transceiver slot.\n" +msgid "NIC-8000-4X.action" +msgstr "Remove and check the transceiver module. It may be faulty,\ninserted incorrectly, or not of the correct type for the slot.\nIf problems persist, consider replacing the module.\n" diff --git a/usr/src/cmd/fm/eversholt/files/common/nic.esc b/usr/src/cmd/fm/eversholt/files/common/nic.esc new file mode 100644 index 0000000000..6dfaf5fa5b --- /dev/null +++ b/usr/src/cmd/fm/eversholt/files/common/nic.esc @@ -0,0 +1,127 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ +/* + * Copyright 2020, the University of Queensland + */ + +#pragma dictionary "NIC" + +/* + * Rules for the generic NIC (non-driver-specific) fault events. + */ + +/* + * Transceiver events are emitted by drivers under ereport.io.nic.txr-err. + * + * These are emitted with detector = the PCI/PCIex function of the NIC. + * They must always have a string property "error", set to one of the + * generic transceiver fault type names (notsupp, whitelist, overtemp etc). + * + * As well as "error", they must have both the "port_index" and "txr_index" + * properties set in the event payload (both integer types). + * + * It is expected that drivers will call ddi_fm_service_impact() immediately + * after noticing a transceiver error, with an argument of DDI_SERVICE_LOST or + * DDI_SERVICE_DEGRADED (depending on the specific error -- at time of writing + * all the supported events expect DDI_SERVICE_LOST). + */ + +asru pcifn; +fru pcifn/port/transceiver; + +asru pciexfn; +fru pciexfn/port/transceiver; + +#define EV_DECL_TXR_FAULT(TYPE) \ + event fault.io.nic.transceiver.TYPE@pcifn/port/transceiver \ + FRU=pcifn/port/transceiver, ASRU=pcifn; \ + event fault.io.nic.transceiver.TYPE@pciexfn/port/transceiver \ + FRU=pciexfn/port/transceiver, ASRU=pciexfn; + +EV_DECL_TXR_FAULT(notsupp) +EV_DECL_TXR_FAULT(whitelist) +EV_DECL_TXR_FAULT(overtemp) +EV_DECL_TXR_FAULT(hwfail) +EV_DECL_TXR_FAULT(unknown) + +event ereport.io.nic.txr-err@pcifn; +event ereport.io.service.lost@pcifn; + +event ereport.io.nic.txr-err@pciexfn; +event ereport.io.service.lost@pciexfn; + +#define EV_PROP_TXR_FAULT(TYPE) \ + prop fault.io.nic.transceiver.TYPE@pcifn/port[pn]/transceiver[tn] (2) -> \ + ereport.io.nic.txr-err@pcifn { \ + payloadprop("txr_index") == tn && \ + payloadprop("port_index") == pn && \ + payloadprop("error") == "TYPE" && \ + setpayloadprop("txr_index", tn) && \ + setpayloadprop("link-name", confprop(pcifn/port[pn], "link-name")) && \ + setpayloadprop("primary-mac-address", confprop(pcifn/port[pn], "primary-mac-address")) && \ + (!confprop_defined(pcifn/port[pn]/transceiver[tn], "vendor") || \ + setpayloadprop("vendor", confprop(pcifn/port[pn]/transceiver[tn], "vendor"))) \ + }, \ + ereport.io.service.lost@pcifn { within(1s) }; \ + prop fault.io.nic.transceiver.TYPE@pciexfn/port[pn]/transceiver[tn] (2) -> \ + ereport.io.nic.txr-err@pciexfn { \ + payloadprop("txr_index") == tn && \ + payloadprop("port_index") == pn && \ + payloadprop("error") == "TYPE" && \ + setpayloadprop("txr_index", tn) && \ + setpayloadprop("link-name", confprop(pciexfn/port[pn], "link-name")) && \ + setpayloadprop("primary-mac-address", confprop(pciexfn/port[pn], "primary-mac-address")) && \ + (!confprop_defined(pciexfn/port[pn]/transceiver[tn], "vendor") || \ + setpayloadprop("vendor", confprop(pciexfn/port[pn]/transceiver[tn], "vendor"))) \ + }, \ + ereport.io.service.lost@pciexfn { within(1s) }; + +EV_PROP_TXR_FAULT(notsupp) +EV_PROP_TXR_FAULT(whitelist) +EV_PROP_TXR_FAULT(overtemp) +EV_PROP_TXR_FAULT(hwfail) +EV_PROP_TXR_FAULT(unknown) + +/* + * Allow drivers (e.g. i40e) which can't tell the difference between the events + * notsupp/unknown/whitelist to generate a single ereport covering all 3. + * + * If transceiver information is available in topo, we will turn it into + * a "notsupp" fault. If it isn't, we'll turn it into an "unknown" fault + * instead. The text in "notsupp" explicitly notes that certain drivers might + * have difficulty telling the difference between it and "whitelist". + * + * If you want this for a pcifn driver rather than pciexfn, you'll have to + * make another copy. + */ +prop fault.io.nic.transceiver.notsupp@pciexfn/port[pn]/transceiver[tn] (2) -> + ereport.io.nic.txr-err@pciexfn { + payloadprop("txr_index") == tn && + payloadprop("port_index") == pn && + payloadprop("error") == "notsupp/unknown" && + confprop_defined(pciexfn/port[pn]/transceiver[tn], "vendor") && + setpayloadprop("txr_index", tn) && + setpayloadprop("link-name", confprop(pciexfn/port[pn], "link-name")) && + setpayloadprop("primary-mac-address", confprop(pciexfn/port[pn], "primary-mac-address")) && + setpayloadprop("vendor", confprop(pciexfn/port[pn]/transceiver[tn], "vendor")) + }, + ereport.io.service.lost@pciexfn { within(1s) }; +prop fault.io.nic.transceiver.unknown@pciexfn/port[pn]/transceiver[tn] (2) -> + ereport.io.nic.txr-err@pciexfn { + payloadprop("txr_index") == tn && + payloadprop("port_index") == pn && + payloadprop("error") == "notsupp/unknown" && + !confprop_defined(pciexfn/port[pn]/transceiver[tn], "vendor") && + setpayloadprop("txr_index", tn) && + setpayloadprop("link-name", confprop(pciexfn/port[pn], "link-name")) && + setpayloadprop("primary-mac-address", confprop(pciexfn/port[pn], "primary-mac-address")) + }, + ereport.io.service.lost@pciexfn { within(1s) }; diff --git a/usr/src/cmd/fm/eversholt/files/i386/Makefile b/usr/src/cmd/fm/eversholt/files/i386/Makefile index bb6cda3b38..67caa4468e 100644 --- a/usr/src/cmd/fm/eversholt/files/i386/Makefile +++ b/usr/src/cmd/fm/eversholt/files/i386/Makefile @@ -33,7 +33,8 @@ EFT_COMMON_FILES= \ sca500.eft \ sca1000.eft \ sensor.eft \ - storage.eft + storage.eft \ + nic.eft include ../../../Makefile.subdirs diff --git a/usr/src/cmd/fm/eversholt/files/sparc/Makefile b/usr/src/cmd/fm/eversholt/files/sparc/Makefile index 4e5655cbf7..0482b12b33 100644 --- a/usr/src/cmd/fm/eversholt/files/sparc/Makefile +++ b/usr/src/cmd/fm/eversholt/files/sparc/Makefile @@ -34,7 +34,8 @@ EFT_COMMON_FILES= \ sca500.eft \ sca1000.eft \ sensor.eft \ - storage.eft + storage.eft \ + nic.eft include ../../../Makefile.subdirs diff --git a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf index 373721a966..a4800aa033 100644 --- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf +++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf @@ -282,6 +282,7 @@ file path=usr/lib/locale/C/LC_MESSAGES/FMD.po file path=usr/lib/locale/C/LC_MESSAGES/FMNOTIFY.po file path=usr/lib/locale/C/LC_MESSAGES/GMCA.po file path=usr/lib/locale/C/LC_MESSAGES/INTEL.po +file path=usr/lib/locale/C/LC_MESSAGES/NIC.po file path=usr/lib/locale/C/LC_MESSAGES/NXGE.po file path=usr/lib/locale/C/LC_MESSAGES/PCI.po file path=usr/lib/locale/C/LC_MESSAGES/PCIEX.po diff --git a/usr/src/pkg/manifests/service-fault-management.mf b/usr/src/pkg/manifests/service-fault-management.mf index 5127927e5b..18e07dd5fc 100644 --- a/usr/src/pkg/manifests/service-fault-management.mf +++ b/usr/src/pkg/manifests/service-fault-management.mf @@ -335,6 +335,8 @@ $(i386_ONLY)file path=usr/lib/fm/dict/GMCA.dict mode=0444 \ variant.opensolaris.zone=__NODEFAULT $(i386_ONLY)file path=usr/lib/fm/dict/INTEL.dict mode=0444 \ variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/fm/dict/NIC.dict mode=0444 \ + variant.opensolaris.zone=__NODEFAULT file path=usr/lib/fm/dict/NXGE.dict mode=0444 \ variant.opensolaris.zone=__NODEFAULT file path=usr/lib/fm/dict/PCI.dict mode=0444 \ @@ -366,6 +368,7 @@ file path=usr/lib/fm/eft/disk.eft mode=0444 \ variant.opensolaris.zone=__NODEFAULT file path=usr/lib/fm/eft/neptune_xaui.eft mode=0444 file path=usr/lib/fm/eft/neptune_xfp.eft mode=0444 +file path=usr/lib/fm/eft/nic.eft mode=0444 file path=usr/lib/fm/eft/pci.eft mode=0444 file path=usr/lib/fm/eft/pciex.eft mode=0444 file path=usr/lib/fm/eft/pciexrc.eft mode=0444 @@ -531,6 +534,8 @@ $(i386_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/GMCA.mo mode=0444 \ variant.opensolaris.zone=__NODEFAULT $(i386_ONLY)file path=usr/lib/locale/C/LC_MESSAGES/INTEL.mo mode=0444 \ variant.opensolaris.zone=__NODEFAULT +file path=usr/lib/locale/C/LC_MESSAGES/NIC.mo mode=0444 \ + variant.opensolaris.zone=__NODEFAULT file path=usr/lib/locale/C/LC_MESSAGES/NXGE.mo mode=0444 \ variant.opensolaris.zone=__NODEFAULT file path=usr/lib/locale/C/LC_MESSAGES/PCI.mo mode=0444 \ diff --git a/usr/src/uts/common/sys/fm/io/ddi.h b/usr/src/uts/common/sys/fm/io/ddi.h index 75afff5c38..d8c772cdaf 100644 --- a/usr/src/uts/common/sys/fm/io/ddi.h +++ b/usr/src/uts/common/sys/fm/io/ddi.h @@ -66,6 +66,17 @@ extern "C" { #define DVR_STACK_DEPTH "dvr-stack-depth" #define DVR_ERR_SPECIFIC "dvr-error-specific" +/* Generic NIC driver ereports. */ +#define DDI_FM_NIC "nic" +#define DDI_FM_TXR_ERROR "txr-err" + +/* Valid values of the "error" field in txr-err ereports */ +#define DDI_FM_TXR_ERROR_WHITELIST "whitelist" +#define DDI_FM_TXR_ERROR_NOTSUPP "notsupp" +#define DDI_FM_TXR_ERROR_OVERTEMP "overtemp" +#define DDI_FM_TXR_ERROR_HWFAIL "hwfail" +#define DDI_FM_TXR_ERROR_UNKNOWN "unknown" + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 8950e535f42dd006f8cfb2122c94f6b7557757e0 Mon Sep 17 00:00:00 2001 From: Andy Fiddaman Date: Sun, 26 Jan 2020 11:58:12 +0000 Subject: 12261 pfiles(1) could show any filesystem endpoints for a door Reviewed by: John Levon Reviewed by: Jason King Approved by: Robert Mustacchi --- usr/src/cmd/ptools/pfiles/pfiles.c | 13 ++++--- usr/src/uts/common/fs/namefs/namevfs.c | 27 +++++++++++++ usr/src/uts/common/fs/proc/prsubr.c | 70 ++++++++++++++++++++++++++++++---- usr/src/uts/common/sys/fs/namenode.h | 8 ++++ usr/src/uts/intel/procfs/Makefile | 3 ++ usr/src/uts/sparc/procfs/Makefile | 20 ++-------- 6 files changed, 111 insertions(+), 30 deletions(-) (limited to 'usr/src/uts/common/sys') diff --git a/usr/src/cmd/ptools/pfiles/pfiles.c b/usr/src/cmd/ptools/pfiles/pfiles.c index ad74bb72ae..dd5ce4af11 100644 --- a/usr/src/cmd/ptools/pfiles/pfiles.c +++ b/usr/src/cmd/ptools/pfiles/pfiles.c @@ -205,13 +205,19 @@ intr(int sig) /* ------ begin specific code ------ */ +static int +show_paths(uint_t type, const void *data, size_t len, void *arg __unused) +{ + if (type == PR_PATHNAME) + (void) printf(" %.*s\n", len, data); + return (0); +} static int show_file(void *data, const prfdinfo_t *info) { struct ps_prochandle *Pr = data; char unknown[12]; - const char *path; char *s; mode_t mode; @@ -259,8 +265,6 @@ show_file(void *data, const prfdinfo_t *info) (void) printf(" rdev:%u,%u\n", (unsigned)info->pr_rmajor, (unsigned)info->pr_rminor); - path = proc_fdinfo_misc(info, PR_PATHNAME, NULL); - if (!nflag) { dofcntl(Pr, info, (mode & (S_IFMT|S_ENFMT|S_IXGRP)) == (S_IFREG|S_ENFMT), @@ -285,8 +289,7 @@ show_file(void *data, const prfdinfo_t *info) } } - if (path != NULL) - (void) printf(" %s\n", path); + (void) proc_fdinfowalk(info, show_paths, NULL); if (info->pr_offset != -1) { (void) printf(" offset:%lld\n", diff --git a/usr/src/uts/common/fs/namefs/namevfs.c b/usr/src/uts/common/fs/namefs/namevfs.c index 9952f0a742..63e618de11 100644 --- a/usr/src/uts/common/fs/namefs/namevfs.c +++ b/usr/src/uts/common/fs/namefs/namevfs.c @@ -21,6 +21,7 @@ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017 by Delphix. All rights reserved. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -181,6 +182,31 @@ namefind(vnode_t *vp, vnode_t *mnt) return (np); } +/* + * For each namenode that has nm_filevp == vp, call the provided function + * with the namenode as an argument. This finds all of the namefs entries + * which are mounted on vp; note that there can be more than one. + */ +int +nm_walk_mounts(const vnode_t *vp, nm_walk_mounts_f *func, cred_t *cr, void *arg) +{ + struct namenode *np; + int ret = 0; + + mutex_enter(&ntable_lock); + + for (np = *NM_FILEVP_HASH(vp); np != NULL; np = np->nm_nextp) { + if (np->nm_filevp == vp) { + if ((ret = func(np, cr, arg)) != 0) + break; + } + } + + mutex_exit(&ntable_lock); + + return (ret); +} + /* * Force the unmouting of a file descriptor from ALL of the nodes * that it was mounted to. @@ -480,6 +506,7 @@ nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp) newvp->v_rdev = filevp->v_rdev; newvp->v_data = (caddr_t)nodep; VFS_HOLD(vfsp); + vn_copypath(mvp, newvp); vn_exists(newvp); /* diff --git a/usr/src/uts/common/fs/proc/prsubr.c b/usr/src/uts/common/fs/proc/prsubr.c index fdb823d7ba..b3b6e57458 100644 --- a/usr/src/uts/common/fs/proc/prsubr.c +++ b/usr/src/uts/common/fs/proc/prsubr.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -2508,7 +2509,11 @@ prfdinfopath(proc_t *p, vnode_t *vp, list_t *data, cred_t *cred) size_t pathlen; size_t sz = 0; - pathlen = MAXPATHLEN + 1; + /* + * The global zone's path to a file in a non-global zone can exceed + * MAXPATHLEN. + */ + pathlen = MAXPATHLEN * 2 + 1; pathname = kmem_alloc(pathlen, KM_SLEEP); if (vnodetopath(NULL, vp, pathname, pathlen, cred) == 0) { @@ -2517,6 +2522,7 @@ prfdinfopath(proc_t *p, vnode_t *vp, list_t *data, cred_t *cred) } kmem_free(pathname, pathlen); + return (sz); } @@ -2745,6 +2751,22 @@ prfdinfosockopt(vnode_t *vp, list_t *data, cred_t *cred) return (sz); } +typedef struct prfdinfo_nm_path_cbdata { + proc_t *nmp_p; + u_offset_t nmp_sz; + list_t *nmp_data; +} prfdinfo_nm_path_cbdata_t; + +static int +prfdinfo_nm_path(const struct namenode *np, cred_t *cred, void *arg) +{ + prfdinfo_nm_path_cbdata_t *cb = arg; + + cb->nmp_sz += prfdinfopath(cb->nmp_p, np->nm_vnode, cb->nmp_data, cred); + + return (0); +} + u_offset_t prgetfdinfosize(proc_t *p, vnode_t *vp, cred_t *cred) { @@ -2757,8 +2779,23 @@ prgetfdinfosize(proc_t *p, vnode_t *vp, cred_t *cred) sz = offsetof(prfdinfo_t, pr_misc) + sizeof (pr_misc_header_t); /* Pathname */ - if (vp->v_type != VSOCK && vp->v_type != VDOOR) + switch (vp->v_type) { + case VDOOR: { + prfdinfo_nm_path_cbdata_t cb = { + .nmp_p = p, + .nmp_data = NULL, + .nmp_sz = 0 + }; + + (void) nm_walk_mounts(vp, prfdinfo_nm_path, cred, &cb); + sz += cb.nmp_sz; + break; + } + case VSOCK: + break; + default: sz += prfdinfopath(p, vp, NULL, cred); + } /* Socket options */ if (vp->v_type == VSOCK) @@ -2902,14 +2939,31 @@ prgetfdinfo(proc_t *p, vnode_t *vp, prfdinfo_t *fdinfo, cred_t *cred, } } - /* - * Don't attempt to determine the vnode path for a socket or a door - * as it will cause a linear scan of the dnlc table given there is no - * v_path associated with the vnode. - */ - if (vp->v_type != VSOCK && vp->v_type != VDOOR) + /* pathname */ + + switch (vp->v_type) { + case VDOOR: { + prfdinfo_nm_path_cbdata_t cb = { + .nmp_p = p, + .nmp_data = data, + .nmp_sz = 0 + }; + + (void) nm_walk_mounts(vp, prfdinfo_nm_path, cred, &cb); + break; + } + case VSOCK: + /* + * Don't attempt to determine the path for a socket as the + * vnode has no associated v_path. It will cause a linear scan + * of the dnlc table and result in no path being found. + */ + break; + default: (void) prfdinfopath(p, vp, data, cred); + } + /* socket options */ if (vp->v_type == VSOCK) (void) prfdinfosockopt(vp, data, cred); diff --git a/usr/src/uts/common/sys/fs/namenode.h b/usr/src/uts/common/sys/fs/namenode.h index 9ebf2cf1ca..24d276b6c3 100644 --- a/usr/src/uts/common/sys/fs/namenode.h +++ b/usr/src/uts/common/sys/fs/namenode.h @@ -26,6 +26,10 @@ * Use is subject to license terms. */ +/* + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + */ + #ifndef _SYS_FS_NAMENODE_H #define _SYS_FS_NAMENODE_H @@ -93,6 +97,10 @@ extern struct vnodeops *nm_vnodeops; extern const struct fs_operation_def nm_vnodeops_template[]; extern kmutex_t ntable_lock; +typedef int nm_walk_mounts_f(const struct namenode *, cred_t *, void *); +extern int nm_walk_mounts(const vnode_t *, nm_walk_mounts_f *, cred_t *, + void *); + #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/intel/procfs/Makefile b/usr/src/uts/intel/procfs/Makefile index 1db5848438..630b6a25d3 100644 --- a/usr/src/uts/intel/procfs/Makefile +++ b/usr/src/uts/intel/procfs/Makefile @@ -25,6 +25,7 @@ # Use is subject to license terms. # # Copyright 2019 Joyent, Inc. +# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. # # This makefile drives the production of the procfs file system @@ -83,6 +84,8 @@ $(OBJS_DIR)/prsubr.o := SMOFF += all_func_returns $(OBJS_DIR)/prcontrol.o := SMOFF += all_func_returns $(OBJS_DIR)/prioctl.o := SMOFF += signed +LDFLAGS += -dy -Nfs/namefs + # # Default build targets. # diff --git a/usr/src/uts/sparc/procfs/Makefile b/usr/src/uts/sparc/procfs/Makefile index 8dd05fe72b..3226238bd4 100644 --- a/usr/src/uts/sparc/procfs/Makefile +++ b/usr/src/uts/sparc/procfs/Makefile @@ -23,6 +23,7 @@ # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. # # This makefile drives the production of the procfs file system @@ -41,7 +42,6 @@ UTSBASE = ../.. # MODULE = procfs OBJECTS = $(PROC_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(PROC_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_FS_DIR)/$(MODULE) # @@ -53,7 +53,6 @@ include $(UTSBASE)/sparc/Makefile.sparc # Define targets # ALL_TARGET = $(BINARY) -LINT_TARGET = $(MODULE).lint INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # @@ -64,19 +63,12 @@ $(MODSTUBS_O) := AS_CPPFLAGS += -DPROC_MODULE CLEANFILES += $(MODSTUBS_O) CFLAGS += $(CCVERBOSE) -# -# For now, disable these lint checks; maintainers should endeavor -# to investigate and remove these for maximum lint coverage. -# Please do not carry these forward to new Makefiles. -# -LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN -LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW -LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV - CERRWARN += -_gcc=-Wno-parentheses CERRWARN += -_gcc=-Wno-switch CERRWARN += $(CNOWARN_UNINIT) +LDFLAGS += -dy -Nfs/namefs + # # Default build targets. # @@ -90,12 +82,6 @@ clean: $(CLEAN_DEPS) clobber: $(CLOBBER_DEPS) -lint: $(LINT_DEPS) - -modlintlib: $(MODLINTLIB_DEPS) - -clean.lint: $(CLEAN_LINT_DEPS) - install: $(INSTALL_DEPS) # -- cgit v1.2.3 From 7d8deab2c421c563ab11a55e623ed48109e237af Mon Sep 17 00:00:00 2001 From: Andy Fiddaman Date: Fri, 14 Feb 2020 11:58:47 +0000 Subject: 12306 XPG4v2 slave pty behaviour should generally be disabled Reviewed by: Robert Mustacchi Reviewed by: John Levon Approved by: Dan McDonald --- usr/src/cmd/ed/ed.c | 29 +- usr/src/cmd/zlogin/zlogin.c | 16 +- usr/src/head/stdlib.h | 15 +- usr/src/lib/libc/port/gen/pt.c | 47 ++- usr/src/lib/libc/port/mapfile-vers | 7 +- usr/src/lib/libc/port/sys/open.c | 123 +----- usr/src/man/man3lib/libc.3lib | 749 ++++++++++++++++++------------------- usr/src/man/man7d/pts.7d | 32 +- usr/src/uts/common/io/ldterm.c | 5 +- usr/src/uts/common/io/ptm.c | 11 +- usr/src/uts/common/io/pts.c | 13 +- usr/src/uts/common/os/streamio.c | 54 ++- usr/src/uts/common/sys/strsubr.h | 4 +- 13 files changed, 543 insertions(+), 562 deletions(-) (limited to 'usr/src/uts/common/sys') diff --git a/usr/src/cmd/ed/ed.c b/usr/src/cmd/ed/ed.c index e8593cadbf..a2fae9c409 100644 --- a/usr/src/cmd/ed/ed.c +++ b/usr/src/cmd/ed/ed.c @@ -24,7 +24,7 @@ */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ -/* All Rights Reserved */ +/* All Rights Reserved */ /* * Editor @@ -41,7 +41,7 @@ #include #include -static const char *msgtab[] = +static const char *msgtab[] = { "write or open on pipe failed", /* 0 */ "warning: expecting `w'", /* 1 */ @@ -161,7 +161,6 @@ static const char *msgtab[] = extern char *optarg; /* Value of argument */ extern int optind; /* Indicator of argument */ -extern int __xpg4; /* defined in xpg4.c; 0 if not xpg4-compiled program */ struct Fspec { char Ftabs[22]; @@ -253,15 +252,15 @@ static int fflg, shflg; static char prompt[16] = "*"; static int rflg; static int readflg; -static int eflg; -static int qflg = 0; -static int ncflg; -static int listn; -static int listf; -static int pflag; -static int flag28 = 0; /* Prevents write after a partial read */ -static int save28 = 0; /* Flag whether buffer empty at start of read */ -static long savtime; +static int eflg; +static int qflg = 0; +static int ncflg; +static int listn; +static int listf; +static int pflag; +static int flag28 = 0; /* Prevents write after a partial read */ +static int save28 = 0; /* Flag whether buffer empty at start of read */ +static long savtime; static char *name = "SHELL"; static char *rshell = "/usr/lib/rsh"; static char *val; @@ -466,7 +465,7 @@ main(int argc, char **argv) ; globp = "e"; fflg++; - } else /* editing with no file so set savtime to 0 */ + } else /* editing with no file so set savtime to 0 */ savtime = 0; eflg++; if ((tfname = tempnam("", "ea")) == NULL) { @@ -3061,8 +3060,8 @@ static char stdtabs[] = { 'f', 0, 1, 7, 11, 15, 19, 23, 0, /* FORTRAN */ 'p', 0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0, /* PL/I */ -'s', 0, 1, 10, 55, 0, /* SNOBOL */ -'u', 0, 1, 12, 20, 44, 0, /* UNIVAC ASM */ +'s', 0, 1, 10, 55, 0, /* SNOBOL */ +'u', 0, 1, 12, 20, 44, 0, /* UNIVAC ASM */ 0 }; diff --git a/usr/src/cmd/zlogin/zlogin.c b/usr/src/cmd/zlogin/zlogin.c index dff46227f2..e942e66e71 100644 --- a/usr/src/cmd/zlogin/zlogin.c +++ b/usr/src/cmd/zlogin/zlogin.c @@ -24,7 +24,7 @@ * Copyright (c) 2014 Gary Mills * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright 2019 Joyent, Inc. - * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ /* @@ -115,8 +115,6 @@ static int pollerr = 0; static const char *pname; static char *username; -extern int __xpg4; /* 0 if not an xpg4/6-compiled program */ - /* * When forced_login is true, the user is not prompted * for an authentication password in the target zone. @@ -770,16 +768,8 @@ process_output(int in_fd, int out_fd) cc = read(in_fd, ibuf, ZLOGIN_BUFSIZ); if (cc == -1 && (errno != EINTR || dead)) return (-1); - if (cc == 0) { - /* - * A return value of 0 when calling read() on a terminal - * indicates end-of-file pre-XPG4 and no data available - * for XPG4 and above. - */ - if (__xpg4 == 0) - return (-1); - return (0); - } + if (cc == 0) + return (-1); /* EOF */ if (cc == -1) /* The read was interrupted. */ return (0); diff --git a/usr/src/head/stdlib.h b/usr/src/head/stdlib.h index 6b0d224e07..337311a978 100644 --- a/usr/src/head/stdlib.h +++ b/usr/src/head/stdlib.h @@ -28,7 +28,7 @@ /* * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. - * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ /* Copyright (c) 1988 AT&T */ @@ -250,6 +250,19 @@ extern int setenv(const char *, const char *, int); extern int unsetenv(const char *); #endif +/* + * In strict XPG4v2 mode, slave pseudo terminal devices behave differently. + * See the block comment in usr/src/lib/libc/port/gen/pt.c + */ +#if defined(_STRICT_SYMBOLS) && defined(_XPG4_2) +#ifdef __PRAGMA_REDEFINE_EXTNAME +#pragma redefine_extname unlockpt __unlockpt_xpg4 +#else +extern int __unlockpt_xpg4(int); +#define unlockpt __unlockpt_xpg4 +#endif +#endif /* defined(_STRICT_SYMBOLS) && defined(_XPG4_2) */ + #if defined(__EXTENSIONS__) || \ (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) extern char *canonicalize_file_name(const char *); diff --git a/usr/src/lib/libc/port/gen/pt.c b/usr/src/lib/libc/port/gen/pt.c index 26dd4dd376..3372f7133c 100644 --- a/usr/src/lib/libc/port/gen/pt.c +++ b/usr/src/lib/libc/port/gen/pt.c @@ -24,10 +24,12 @@ * Use is subject to license terms. */ -/* Copyright (c) 1988 AT&T */ -/* All Rights Reserved */ +/* + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* Copyright (c) 1988 AT&T */ +/* All Rights Reserved */ #pragma weak _ptsname = ptsname #pragma weak _grantpt = grantpt @@ -133,6 +135,45 @@ unlockpt(int fd) return (0); } +/* + * XPG4v2 requires that open of a slave pseudo terminal device + * provides the process with an interface that is identical to + * the terminal interface. + * + * To satisfy this, in strict XPG4v2 mode, this routine also sends + * a message down the stream that sets a flag in the kernel module + * so that additional actions are performed when opening an + * associated slave PTY device. When this happens, modules are + * automatically pushed onto the stream to provide terminal + * semantics and those modules are then informed that they should + * behave in strict XPG4v2 mode which modifies their behaviour. In + * particular, in strict XPG4v2 mode, empty blocks will be sent up + * the master side of the stream rather than being suppressed. + * + * Most applications do not expect this behaviour so it is only + * enabled for programs compiled in strict XPG4v2 mode (see + * stdlib.h). + */ +int +__unlockpt_xpg4(int fd) +{ + int ret; + + if ((ret = unlockpt(fd)) == 0) { + struct strioctl istr; + + istr.ic_cmd = PTSSTTY; + istr.ic_len = 0; + istr.ic_timout = 0; + istr.ic_dp = NULL; + + if (ioctl(fd, I_STR, &istr) < 0) + ret = -1; + } + + return (ret); +} + int grantpt(int fd) { diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers index e4cf0e299a..8f33fda6d4 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -27,7 +27,7 @@ # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. # Copyright (c) 2013 Gary Mills # Copyright 2014 Garrett D'Amore -# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. # # @@ -78,6 +78,11 @@ $if _x86 && _ELF64 $add amd64 $endif +SYMBOL_VERSION ILLUMOS_0.31 { + protected: + __unlockpt_xpg4; +} ILLUMOS_0.30; + SYMBOL_VERSION ILLUMOS_0.30 { protected: reallocf; diff --git a/usr/src/lib/libc/port/sys/open.c b/usr/src/lib/libc/port/sys/open.c index 067bb72d69..2ea6c567f4 100644 --- a/usr/src/lib/libc/port/sys/open.c +++ b/usr/src/lib/libc/port/sys/open.c @@ -22,44 +22,32 @@ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ /* Copyright (c) 1988 AT&T */ -/* All Rights Reserved */ +/* All Rights Reserved */ #include "lint.h" -#include #include #include #include -#include -#include -#include #include -#include -#include -#include #include #include "libc.h" -static int xpg4_fixup(int fd); -static void push_module(int fd); -static int isptsfd(int fd); -static void itoa(int i, char *ptr); - int __openat(int dfd, const char *path, int oflag, mode_t mode) { - int fd = syscall(SYS_openat, dfd, path, oflag, mode); - return (xpg4_fixup(fd)); + return (syscall(SYS_openat, dfd, path, oflag, mode)); } int __open(const char *path, int oflag, mode_t mode) { #if defined(_RETAIN_OLD_SYSCALLS) - int fd = syscall(SYS_open, path, oflag, mode); - return (xpg4_fixup(fd)); + return (syscall(SYS_open, path, oflag, mode)); #else return (__openat(AT_FDCWD, path, oflag, mode)); #endif @@ -70,114 +58,17 @@ __open(const char *path, int oflag, mode_t mode) int __openat64(int dfd, const char *path, int oflag, mode_t mode) { - int fd = syscall(SYS_openat64, dfd, path, oflag, mode); - return (xpg4_fixup(fd)); + return (syscall(SYS_openat64, dfd, path, oflag, mode)); } int __open64(const char *path, int oflag, mode_t mode) { #if defined(_RETAIN_OLD_SYSCALLS) - int fd = syscall(SYS_open64, path, oflag, mode); - return (xpg4_fixup(fd)); + return (syscall(SYS_open64, path, oflag, mode)); #else return (__openat64(AT_FDCWD, path, oflag, mode)); #endif } #endif /* !_LP64 */ - -/* - * XPG4v2 requires that open of a slave pseudo terminal device - * provides the process with an interface that is identical to - * the terminal interface. For a more detailed discussion, - * see bugid 4025044. - */ -static int -xpg4_fixup(int fd) -{ - if (libc__xpg4 != 0 && fd >= 0 && isptsfd(fd)) - push_module(fd); - return (fd); -} - -/* - * Check if the file matches an entry in the /dev/pts directory. - * Be careful to preserve errno. - */ -static int -isptsfd(int fd) -{ - char buf[TTYNAME_MAX]; - char *str1 = buf; - const char *str2 = "/dev/pts/"; - struct stat64 fsb, stb; - int oerrno = errno; - int rval = 0; - - if (fstat64(fd, &fsb) == 0 && S_ISCHR(fsb.st_mode)) { - /* - * Do this without strcpy() or strlen(), - * to avoid invoking the dynamic linker. - */ - while (*str2 != '\0') - *str1++ = *str2++; - /* - * Inline version of minor(dev), to avoid the dynamic linker. - */ - itoa(fsb.st_rdev & MAXMIN, str1); - if (stat64(buf, &stb) == 0) - rval = (stb.st_rdev == fsb.st_rdev); - } - errno = oerrno; - return (rval); -} - -/* - * Converts a number to a string (null terminated). - */ -static void -itoa(int i, char *ptr) -{ - int dig = 0; - int tempi; - - tempi = i; - do { - dig++; - tempi /= 10; - } while (tempi); - - ptr += dig; - *ptr = '\0'; - while (--dig >= 0) { - *(--ptr) = i % 10 + '0'; - i /= 10; - } -} - -/* - * Push modules to provide tty semantics - */ -static void -push_module(int fd) -{ - struct strioctl istr; - int oerrno = errno; - - istr.ic_cmd = PTSSTTY; - istr.ic_len = 0; - istr.ic_timout = 0; - istr.ic_dp = NULL; - if (ioctl(fd, I_STR, &istr) != -1) { - (void) ioctl(fd, __I_PUSH_NOCTTY, "ptem"); - (void) ioctl(fd, __I_PUSH_NOCTTY, "ldterm"); - (void) ioctl(fd, __I_PUSH_NOCTTY, "ttcompat"); - istr.ic_cmd = PTSSTTY; - istr.ic_len = 0; - istr.ic_timout = 0; - istr.ic_dp = NULL; - (void) ioctl(fd, I_STR, &istr); - } - errno = oerrno; -} diff --git a/usr/src/man/man3lib/libc.3lib b/usr/src/man/man3lib/libc.3lib index 3978eabae8..83df10408b 100644 --- a/usr/src/man/man3lib/libc.3lib +++ b/usr/src/man/man3lib/libc.3lib @@ -1,4 +1,5 @@ '\" te +.\" Copyright 2020 OmniOS Community Edition (OmniOSce) Association. .\" Copyright 2014 Garrett D'Amore .\" Copyright (c) 2009, Sun Microsystems, Inc. All rights reserved. .\" Copyright 2016 Joyent, Inc. @@ -6,7 +7,7 @@ .\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with .\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] .\" Copyright 2011 by Delphix. All rights reserved. -.TH LIBC 3LIB "Dec 10, 2015" +.TH LIBC 3LIB "Feb 14, 2020" .SH NAME libc \- C library .SH DESCRIPTION @@ -43,54 +44,54 @@ l l . \fB__posix_sigwait\fR \fB__posix_ttyname_r\fR \fB__priocntl\fR \fB__priocntlset\fR \fB__pthread_cleanup_pop\fR \fB__pthread_cleanup_push\fR -\fB__sysconf_xpg5\fR \fB__xpg4\fR -\fB__xpg4_putmsg\fR \fB__xpg4_putpmsg\fR -\fB_Exit\fR \fB_altzone\fR -\fB_assert\fR \fB_cleanup\fR -\fB_ctype\fR \fB_daylight\fR -\fB_environ\fR \fB_exit\fR -\fB_exithandle\fR \fB_filbuf\fR -\fB_flsbuf\fR \fB_flushlbf\fR -\fB_getdate_err\fR \fB_getdate_err_addr\fR -\fB_iob\fR \fB_isnan\fR -\fB_isnand\fR \fB_lwp_cond_broadcast\fR -\fB_lwp_cond_reltimedwait\fR \fB_lwp_cond_signal\fR -\fB_lwp_cond_timedwait\fR \fB_lwp_cond_wait\fR -\fB_lwp_continue\fR \fB_lwp_info\fR -\fB_lwp_kill\fR \fB_lwp_mutex_lock\fR -\fB_lwp_mutex_trylock\fR \fB_lwp_mutex_unlock\fR -\fB_lwp_self\fR \fB_lwp_sema_init\fR -\fB_lwp_sema_post\fR \fB_lwp_sema_trywait\fR -\fB_lwp_sema_wait\fR \fB_lwp_suspend\fR -\fB_lwp_suspend2\fR \fB_modf\fR -\fB_nextafter\fR \fB_nsc_trydoorcall\fR -\fB_nss_XbyY_buf_alloc\fR \fB_nss_XbyY_buf_free\fR -\fB_nss_netdb_aliases\fR \fB_numeric\fR -\fB_scalb\fR \fB_sibuf\fR -\fB_sobuf\fR \fB_stack_grow\fR -\fB_sys_buslist\fR \fB_sys_cldlist\fR -\fB_sys_fpelist\fR \fB_sys_illlist\fR -\fB_sys_segvlist\fR \fB_sys_siginfolistp\fR -\fB_sys_siglist\fR \fB_sys_siglistn\fR -\fB_sys_siglistp\fR \fB_sys_traplist\fR -\fB_timezone\fR \fB_tolower\fR -\fB_toupper\fR \fB_tzname\fR -\fB_xftw\fR \fB\fR -\fBa64l\fR \fBabort\fR -\fBabs\fR \fBaccess\fR -\fBacct\fR \fBacl\fR -\fBaddrtosymstr\fR \fBaddsev\fR -\fBaddseverity\fR \fBadjtime\fR -\fBaio_cancel\fR \fBaio_error\fR -\fBaio_fsync\fR \fBaio_read\fR -\fBaio_return\fR \fBaio_suspend\fR -\fBaio_waitn\fR \fBaio_write\fR -\fBaiocancel\fR \fBaioread\fR -\fBaiowait\fR \fBaiowrite\fR -\fBalarm\fR \fBalphasort\fR -\fBaltzone\fR \fBascftime\fR -\fBasctime\fR \fBasctime_r\fR -\fBasprintf\fR +\fB__sysconf_xpg5\fR \fB__unlockpt_xpg4\fR +\fB__xpg4\fR \fB__xpg4_putmsg\fR +\fB__xpg4_putpmsg\fR \fB_Exit\fR +\fB_altzone\fR \fB_assert\fR +\fB_cleanup\fR \fB_ctype\fR +\fB_daylight\fR \fB_environ\fR +\fB_exit\fR \fB_exithandle\fR +\fB_filbuf\fR \fB_flsbuf\fR +\fB_flushlbf\fR \fB_getdate_err\fR +\fB_getdate_err_addr\fR \fB_iob\fR +\fB_isnan\fR \fB_isnand\fR +\fB_lwp_cond_broadcast\fR \fB_lwp_cond_reltimedwait\fR +\fB_lwp_cond_signal\fR \fB_lwp_cond_timedwait\fR +\fB_lwp_cond_wait\fR \fB_lwp_continue\fR +\fB_lwp_info\fR \fB_lwp_kill\fR +\fB_lwp_mutex_lock\fR \fB_lwp_mutex_trylock\fR +\fB_lwp_mutex_unlock\fR \fB_lwp_self\fR +\fB_lwp_sema_init\fR \fB_lwp_sema_post\fR +\fB_lwp_sema_trywait\fR \fB_lwp_sema_wait\fR +\fB_lwp_suspend\fR \fB_lwp_suspend2\fR +\fB_modf\fR \fB_nextafter\fR +\fB_nsc_trydoorcall\fR \fB_nss_XbyY_buf_alloc\fR +\fB_nss_XbyY_buf_free\fR \fB_nss_netdb_aliases\fR +\fB_numeric\fR \fB_scalb\fR +\fB_sibuf\fR \fB_sobuf\fR +\fB_stack_grow\fR \fB_sys_buslist\fR +\fB_sys_cldlist\fR \fB_sys_fpelist\fR +\fB_sys_illlist\fR \fB_sys_segvlist\fR +\fB_sys_siginfolistp\fR \fB_sys_siglist\fR +\fB_sys_siglistn\fR \fB_sys_siglistp\fR +\fB_sys_traplist\fR \fB_timezone\fR +\fB_tolower\fR \fB_toupper\fR +\fB_tzname\fR \fB_xftw\fR +\fB\fR \fBa64l\fR +\fBabort\fR \fBabs\fR +\fBaccess\fR \fBacct\fR +\fBacl\fR \fBaddrtosymstr\fR +\fBaddsev\fR \fBaddseverity\fR +\fBadjtime\fR \fBaio_cancel\fR +\fBaio_error\fR \fBaio_fsync\fR +\fBaio_read\fR \fBaio_return\fR +\fBaio_suspend\fR \fBaio_waitn\fR +\fBaio_write\fR \fBaiocancel\fR +\fBaioread\fR \fBaiowait\fR +\fBaiowrite\fR \fBalarm\fR +\fBalphasort\fR \fBaltzone\fR +\fBascftime\fR \fBasctime\fR +\fBasctime_r\fR \fBasprintf\fR \fBatexit\fR \fBatof\fR \fBatoi\fR \fBatol\fR \fBatoll\fR \fBatomic_add_16\fR @@ -152,10 +153,9 @@ l l . \fBbcmp\fR \fBbcopy\fR \fBbindtextdomain\fR \fBbind_textdomain_codeset\fR \fBbrk\fR \fBbsd_signal\fR -\fBbsearch\fR -\fBbtowc\fR \fBbtowc_l\fR -\fBbzero\fR \fBcalloc\fR -\fBcanonicalize_file_name\fR +\fBbsearch\fR \fBbtowc\fR +\fBbtowc_l\fR \fBbzero\fR +\fBcalloc\fR \fBcanonicalize_file_name\fR \fBcatclose\fR \fBcatgets\fR \fBcatopen\fR \fBcfgetispeed\fR \fBcfgetospeed\fR \fBcfsetispeed\fR @@ -163,22 +163,21 @@ l l . \fBchdir\fR \fBchmod\fR \fBchown\fR \fBchroot\fR \fBclearerr\fR \fBclearenv\fR -\fBclock\fR -\fBclock_getres\fR \fBclock_gettime\fR -\fBclock_nanosleep\fR \fBclock_settime\fR -\fBclose\fR \fBclosedir\fR -\fBclosefrom\fR \fBcloselog\fR -\fBcond_broadcast\fR \fBcond_destroy\fR -\fBcond_init\fR \fBcond_reltimedwait\fR -\fBcond_signal\fR \fBcond_timedwait\fR -\fBcond_wait\fR \fBconfstr\fR -\fBcreat\fR \fBcrypt\fR -\fBcrypt_genhash_impl\fR \fBcrypt_gensalt\fR -\fBcrypt_gensalt_impl\fR \fBcsetcol\fR -\fBcsetlen\fR \fBctermid\fR -\fBctermid_r\fR \fBctime\fR -\fBctime_r\fR \fBcuserid\fR -\fBdaemon\fR +\fBclock\fR \fBclock_getres\fR +\fBclock_gettime\fR \fBclock_nanosleep\fR +\fBclock_settime\fR \fBclose\fR +\fBclosedir\fR \fBclosefrom\fR +\fBcloselog\fR \fBcond_broadcast\fR +\fBcond_destroy\fR \fBcond_init\fR +\fBcond_reltimedwait\fR \fBcond_signal\fR +\fBcond_timedwait\fR \fBcond_wait\fR +\fBconfstr\fR \fBcreat\fR +\fBcrypt\fR \fBcrypt_genhash_impl\fR +\fBcrypt_gensalt\fR \fBcrypt_gensalt_impl\fR +\fBcsetcol\fR \fBcsetlen\fR +\fBctermid\fR \fBctermid_r\fR +\fBctime\fR \fBctime_r\fR +\fBcuserid\fR \fBdaemon\fR \fBdaylight\fR \fBdbm_clearerr\fR \fBdbm_close\fR \fBdbm_delete\fR \fBdbm_error\fR \fBdbm_fetch\fR @@ -203,9 +202,8 @@ l l . \fBdoor_ucred\fR \fBdoor_unbind\fR \fBdouble_to_decimal\fR \fBdrand48\fR \fBdup\fR \fBdup2\fR -\fBduplocale\fR -\fBeconvert\fR \fBecvt\fR -\fBenable_extended_FILE_stdio\fR +\fBduplocale\fR \fBeconvert\fR +\fBecvt\fR \fBenable_extended_FILE_stdio\fR \fBencrypt\fR \fBendgrent\fR \fBendnetgrent\fR \fBendpwent\fR \fBendspent\fR \fBendusershell\fR @@ -218,10 +216,9 @@ l l . \fBexeclp\fR \fBexecv\fR \fBexecve\fR \fBexecvp\fR \fBexit\fR \fBextended_to_decimal\fR -\fBfaccessat\fR -\fBfacl\fR \fBfattach\fR -\fBfchdir\fR \fBfchmod\fR -\fBfchmodat\fR +\fBfaccessat\fR \fBfacl\fR +\fBfattach\fR \fBfchdir\fR +\fBfchmod\fR \fBfchmodat\fR \fBfchown\fR \fBfchownat\fR \fBfchroot\fR \fBfclose\fR \fBfcloseall\fR \fBfcntl\fR @@ -239,69 +236,66 @@ l l . \fBfgetpwent_r\fR \fBfgets\fR \fBfgetspent\fR \fBfgetspent_r\fR \fBfgetwc\fR \fBfgetwc_l\fR -\fBfgetws\fR -\fBfile_to_decimal\fR \fBfileno\fR -\fBfinite\fR \fBflockfile\fR -\fBfmtmsg\fR \fBfnmatch\fR -\fBfopen\fR \fBfork\fR -\fBfork1\fR \fBforkall\fR -\fBforkallx\fR \fBforkx\fR -\fBfpathconf\fR \fBfpclass\fR -\fBfpgetmask\fR \fBfpgetround\fR -\fBfpgetsticky\fR \fBfprintf\fR -\fBfpsetmask\fR \fBfpsetround\fR -\fBfpsetsticky\fR \fBfputc\fR -\fBfputs\fR \fBfputwc\fR -\fBfputws\fR \fBfread\fR -\fBfree\fR \fBfreelocale\fR -\fBfreopen\fR +\fBfgetws\fR \fBfile_to_decimal\fR +\fBfileno\fR \fBfinite\fR +\fBflockfile\fR \fBfmtmsg\fR +\fBfnmatch\fR \fBfopen\fR +\fBfork\fR \fBfork1\fR +\fBforkall\fR \fBforkallx\fR +\fBforkx\fR \fBfpathconf\fR +\fBfpclass\fR \fBfpgetmask\fR +\fBfpgetround\fR \fBfpgetsticky\fR +\fBfprintf\fR \fBfpsetmask\fR +\fBfpsetround\fR \fBfpsetsticky\fR +\fBfputc\fR \fBfputs\fR +\fBfputwc\fR \fBfputws\fR +\fBfread\fR \fBfree\fR +\fBfreelocale\fR \fBfreopen\fR \fBfrexp\fR \fBfscanf\fR \fBfseek\fR \fBfseeko\fR -\fBfsetattr\fR -\fBfsetpos\fR \fBfstat\fR -\fBfstatat\fR \fBfstatfs\fR -\fBfstatvfs\fR \fBfsync\fR -\fBftell\fR \fBftello\fR -\fBftime\fR \fBftok\fR -\fBftruncate\fR \fBftrylockfile\fR -\fBftw\fR \fBfunc_to_decimal\fR -\fBfunlockfile\fR \fBfutimens\fR -\fBfutimesat\fR +\fBfsetattr\fR \fBfsetpos\fR +\fBfstat\fR \fBfstatat\fR +\fBfstatfs\fR \fBfstatvfs\fR +\fBfsync\fR \fBftell\fR +\fBftello\fR \fBftime\fR +\fBftok\fR \fBftruncate\fR +\fBftrylockfile\fR \fBftw\fR +\fBfunc_to_decimal\fR \fBfunlockfile\fR +\fBfutimens\fR \fBfutimesat\fR \fBfwide\fR \fBfwprintf\fR \fBfwrite\fR \fBfwscanf\fR \fBgconvert\fR \fBgcvt\fR \fBgetacct\fR \fBgetattrat\fR -\fBgetc\fR -\fBgetc_unlocked\fR \fBgetchar\fR -\fBgetchar_unlocked\fR \fBgetcontext\fR -\fBgetcpuid\fR \fBgetcwd\fR -\fBgetdate\fR \fBgetdate_err\fR -\fBgetdents\fR \fBgetdtablesize\fR -\fBgetegid\fR \fBgetenv\fR -\fBgeteuid\fR \fBgetexecname\fR -\fBgetextmntent\fR \fBgetgid\fR -\fBgetgrent\fR \fBgetgrent_r\fR -\fBgetgrgid\fR \fBgetgrgid_r\fR -\fBgetgrnam\fR \fBgetgrnam_r\fR -\fBgetgroups\fR \fBgethomelgroup\fR -\fBgethostid\fR \fBgethostname\fR -\fBgethrtime\fR \fBgethrvtime\fR -\fBgetisax\fR \fBgetitimer\fR -\fBgetloadavg\fR \fBgetlogin\fR -\fBgetlogin_r\fR \fBgetmntany\fR -\fBgetmntent\fR \fBgetmsg\fR -\fBget_nprocs\fR \fBget_nprocs_conf\fR -\fBgetnetgrent\fR \fBgetnetgrent_r\fR -\fBgetopt\fR \fBgetopt_clip\fR -\fBgetopt_long\fR \fBgetopt_long_only\fR -\fBgetpagesize\fR \fBgetpagesizes\fR -\fBgetpass\fR \fBgetpassphrase\fR -\fBgetpeerucred\fR \fBgetpflags\fR -\fBgetpgid\fR \fBgetpgrp\fR -\fBgetpid\fR \fBgetpmsg\fR -\fBgetppid\fR \fBgetppriv\fR -\fBgetpriority\fR \fBgetprogname\fR -\fBgetprojid\fR +\fBgetc\fR \fBgetc_unlocked\fR +\fBgetchar\fR \fBgetchar_unlocked\fR +\fBgetcontext\fR \fBgetcpuid\fR +\fBgetcwd\fR \fBgetdate\fR +\fBgetdate_err\fR \fBgetdents\fR +\fBgetdtablesize\fR \fBgetegid\fR +\fBgetenv\fR \fBgeteuid\fR +\fBgetexecname\fR \fBgetextmntent\fR +\fBgetgid\fR \fBgetgrent\fR +\fBgetgrent_r\fR \fBgetgrgid\fR +\fBgetgrgid_r\fR \fBgetgrnam\fR +\fBgetgrnam_r\fR \fBgetgroups\fR +\fBgethomelgroup\fR \fBgethostid\fR +\fBgethostname\fR \fBgethrtime\fR +\fBgethrvtime\fR \fBgetisax\fR +\fBgetitimer\fR \fBgetloadavg\fR +\fBgetlogin\fR \fBgetlogin_r\fR +\fBgetmntany\fR \fBgetmntent\fR +\fBgetmsg\fR \fBget_nprocs\fR +\fBget_nprocs_conf\fR \fBgetnetgrent\fR +\fBgetnetgrent_r\fR \fBgetopt\fR +\fBgetopt_clip\fR \fBgetopt_long\fR +\fBgetopt_long_only\fR \fBgetpagesize\fR +\fBgetpagesizes\fR \fBgetpass\fR +\fBgetpassphrase\fR \fBgetpeerucred\fR +\fBgetpflags\fR \fBgetpgid\fR +\fBgetpgrp\fR \fBgetpid\fR +\fBgetpmsg\fR \fBgetppid\fR +\fBgetppriv\fR \fBgetpriority\fR +\fBgetprogname\fR \fBgetprojid\fR \fBgetpw\fR \fBgetpwent\fR \fBgetpwent_r\fR \fBgetpwnam\fR \fBgetpwnam_r\fR \fBgetpwuid\fR @@ -320,10 +314,9 @@ l l . \fBgetutxid\fR \fBgetutxline\fR \fBgetvfsany\fR \fBgetvfsent\fR \fBgetvfsfile\fR \fBgetvfsspec\fR -\fBgetw\fR -\fBgetwc\fR \fBgetwc_l\fR -\fBgetwchar\fR \fBgetwchar_l\fR -\fBgetwd\fR +\fBgetw\fR \fBgetwc\fR +\fBgetwc_l\fR \fBgetwchar\fR +\fBgetwchar_l\fR \fBgetwd\fR \fBgetwidth\fR \fBgetws\fR \fBgetzoneid\fR \fBgetzoneidbyname\fR \fBgetzonenamebyid\fR \fBglob\fR @@ -337,27 +330,23 @@ l l . \fBindex\fR \fBinitgroups\fR \fBinitstate\fR \fBinnetgr\fR \fBinsque\fR \fBioctl\fR -\fBis_system_labeled\fR -\fBisaexec\fR +\fBis_system_labeled\fR \fBisaexec\fR \fBisalnum\fR \fBisalnum_l\fR \fBisalpha\fR \fBisalpha_l\fR \fBisascii\fR \fBisastream\fR -\fBisatty\fR -\fBisblank\fR \fBisblank_l\fR -\fBiscntrl\fR \fBiscntrl_l\fR -\fBisdigit\fR \fBisdigit_l\fR -\fBisenglish\fR +\fBisatty\fR \fBisblank\fR +\fBisblank_l\fR \fBiscntrl\fR +\fBiscntrl_l\fR \fBisdigit\fR +\fBisdigit_l\fR \fBisenglish\fR \fBisgraph\fR \fBisgraph_l\fR -\fBisideogram\fR -\fBislower\fR \fBislower_l\fR -\fBisnan\fR +\fBisideogram\fR \fBislower\fR +\fBislower_l\fR \fBisnan\fR \fBisnand\fR \fBisnanf\fR \fBisnumber\fR \fBisphonogram\fR \fBisprint\fR \fBisprint_l\fR \fBispunct\fR \fBispunct_l\fR -\fBissetugid\fR -\fBisspace\fR \fBisspace_l\fR -\fBisspecial\fR +\fBissetugid\fR \fBisspace\fR +\fBisspace_l\fR \fBisspecial\fR \fBisupper\fR \fBisupper_l\fR \fBiswalnum\fR \fBiswalnum_l\fR \fBiswalpha\fR \fBiswalpha_l\fR @@ -398,31 +387,29 @@ l l . \fBlsub\fR \fBlten\fR \fBlzero\fR \fBmadvise\fR \fBmakecontext\fR \fBmakeutx\fR -\fBmalloc\fR -\fBmblen\fR \fBmblen_l\fR -\fBmbrlen\fR \fBmbrlen_l\fR -\fBmbrtowc\fR \fBmbrtowc_l\fR -\fBmbsinit\fR \fBmbsinit_l\fR -\fBmbsnrtowcs\fR \fBmbsnrtowcs_l\fR -\fBmbsrtowcs\fR \fBmbsrtowcs_l\fR -\fBmbstowcs\fR \fBmbstowcs_l\fR -\fBmbtowc\fR \fBmbtowc_l\fR -\fBmemalign\fR \fBmembar_consumer\fR -\fBmembar_enter\fR \fBmembar_exit\fR -\fBmembar_producer\fR \fBmemccpy\fR -\fBmemchr\fR \fBmemcmp\fR -\fBmemcntl\fR \fBmemcpy\fR -\fBmeminfo\fR \fBmemmem\fR -\fBmemmove\fR +\fBmalloc\fR \fBmblen\fR +\fBmblen_l\fR \fBmbrlen\fR +\fBmbrlen_l\fR \fBmbrtowc\fR +\fBmbrtowc_l\fR \fBmbsinit\fR +\fBmbsinit_l\fR \fBmbsnrtowcs\fR +\fBmbsnrtowcs_l\fR \fBmbsrtowcs\fR +\fBmbsrtowcs_l\fR \fBmbstowcs\fR +\fBmbstowcs_l\fR \fBmbtowc\fR +\fBmbtowc_l\fR \fBmemalign\fR +\fBmembar_consumer\fR \fBmembar_enter\fR +\fBmembar_exit\fR \fBmembar_producer\fR +\fBmemccpy\fR \fBmemchr\fR +\fBmemcmp\fR \fBmemcntl\fR +\fBmemcpy\fR \fBmeminfo\fR +\fBmemmem\fR \fBmemmove\fR \fBmemset\fR \fBmincore\fR \fBmkdir\fR \fBmkdirat\fR \fBmkfifo\fR \fBmkfifoat\fR \fBmknod\fR \fBmknodat\fR -\fBmkstemp\fR -\fBmktemp\fR \fBmktime\fR -\fBmlock\fR \fBmlockall\fR -\fBmmap\fR \fBmmapobj\fR -\fBmodctl\fR +\fBmkstemp\fR \fBmktemp\fR +\fBmktime\fR \fBmlock\fR +\fBmlockall\fR \fBmmap\fR +\fBmmapobj\fR \fBmodctl\fR \fBmodf\fR \fBmodff\fR \fBmodutx\fR \fBmonitor\fR \fBmount\fR \fBmprotect\fR @@ -445,34 +432,31 @@ l l . \fBnfs_getfh\fR \fBnftw\fR \fBngettext\fR \fBnice\fR \fBnl_langinfo\fR \fBnl_langinfo_l\fR -\fBnrand48\fR -\fBnss_default_finders\fR \fBnss_delete\fR -\fBnss_endent\fR \fBnss_getent\fR -\fBnss_search\fR \fBnss_setent\fR -\fBntp_adjtime\fR \fBntp_gettime\fR -\fBopen\fR \fBopenat\fR -\fBopendir\fR \fBopenlog\fR -\fBoptarg\fR \fBopterr\fR -\fBoptind\fR \fBoptopt\fR -\fBp_online\fR \fBpathconf\fR -\fBpause\fR \fBpclose\fR -\fBpcsample\fR \fBperror\fR -\fBpfmt\fR \fBpipe\fR -\fBplock\fR \fBpoll\fR -\fBpopen\fR \fBport_alert\fR -\fBport_associate\fR \fBport_create\fR -\fBport_dissociate\fR \fBport_get\fR -\fBport_getn\fR \fBport_send\fR -\fBport_sendn\fR \fBposix_fadvise\fR -\fBposix_fallocate\fR \fBposix_madvise\fR -\fBposix_memalign\fR \fBposix_openpt\fR -\fBposix_spawn\fR \fBposix_spawn_file_actions_addclose\fR -\fBposix_spawn_file_actions_addclosefrom_np\fR \fBposix_spawn_file_actions_adddup2\fR -\fBposix_spawn_file_actions_addopen\fR -\fBposix_spawn_file_actions_destroy\fR -\fBposix_spawn_file_actions_init\fR -\fBposix_spawn_pipe_np\fR -\fBposix_spawnattr_destroy\fR +\fBnrand48\fR \fBnss_default_finders\fR +\fBnss_delete\fR \fBnss_endent\fR +\fBnss_getent\fR \fBnss_search\fR +\fBnss_setent\fR \fBntp_adjtime\fR +\fBntp_gettime\fR \fBopen\fR +\fBopenat\fR \fBopendir\fR +\fBopenlog\fR \fBoptarg\fR +\fBopterr\fR \fBoptind\fR +\fBoptopt\fR \fBp_online\fR +\fBpathconf\fR \fBpause\fR +\fBpclose\fR \fBpcsample\fR +\fBperror\fR \fBpfmt\fR +\fBpipe\fR \fBplock\fR +\fBpoll\fR \fBpopen\fR +\fBport_alert\fR \fBport_associate\fR +\fBport_create\fR \fBport_dissociate\fR +\fBport_get\fR \fBport_getn\fR +\fBport_send\fR \fBport_sendn\fR +\fBposix_fadvise\fR \fBposix_fallocate\fR +\fBposix_madvise\fR \fBposix_memalign\fR +\fBposix_openpt\fR \fBposix_spawn\fR +\fBposix_spawn_file_actions_addclose\fR \fBposix_spawn_file_actions_addclosefrom_np\fR +\fBposix_spawn_file_actions_adddup2\fR \fBposix_spawn_file_actions_addopen\fR +\fBposix_spawn_file_actions_destroy\fR \fBposix_spawn_file_actions_init\fR +\fBposix_spawn_pipe_np\fR \fBposix_spawnattr_destroy\fR \fBposix_spawnattr_getflags\fR \fBposix_spawnattr_getpgroup\fR \fBposix_spawnattr_getschedparam\fR \fBposix_spawnattr_getschedpolicy\fR \fBposix_spawnattr_getsigdefault\fR \fBposix_spawnattr_getsigignore_np\fR @@ -482,30 +466,29 @@ l l . \fBposix_spawnattr_setsigdefault\fR \fBposix_spawnattr_setsigignore_np\fR \fBposix_spawnattr_setsigmask\fR \fBposix_spawnp\fR \fBpread\fR \fBpreadv\fR -\fBprintf\fR -\fBprintstack\fR \fBpriocntl\fR -\fBpriocntlset\fR \fBpriv_addset\fR -\fBpriv_allocset\fR \fBpriv_copyset\fR -\fBpriv_delset\fR \fBpriv_emptyset\fR -\fBpriv_fillset\fR \fBpriv_freeset\fR -\fBpriv_getbyname\fR \fBpriv_getbynum\fR -\fBpriv_getsetbyname\fR \fBpriv_getsetbynum\fR -\fBpriv_gettext\fR \fBpriv_ineffect\fR -\fBpriv_intersect\fR \fBpriv_inverse\fR -\fBpriv_isemptyset\fR \fBpriv_isequalset\fR -\fBpriv_isfullset\fR \fBpriv_ismember\fR -\fBpriv_issubset\fR \fBpriv_set\fR -\fBpriv_set_to_str\fR \fBpriv_str_to_set\fR -\fBpriv_union\fR \fBprocessor_bind\fR -\fBprocessor_info\fR \fBprofil\fR -\fBpselect\fR \fBpset_assign\fR -\fBpset_bind\fR \fBpset_create\fR -\fBpset_destroy\fR \fBpset_getattr\fR -\fBpset_getloadavg\fR \fBpset_info\fR -\fBpset_list\fR \fBpset_setattr\fR -\fBpsiginfo\fR \fBpsignal\fR -\fBpthread_atfork\fR \fBpthread_attr_destroy\fR -\fBpthread_attr_get_np\fR +\fBprintf\fR \fBprintstack\fR +\fBpriocntl\fR \fBpriocntlset\fR +\fBpriv_addset\fR \fBpriv_allocset\fR +\fBpriv_copyset\fR \fBpriv_delset\fR +\fBpriv_emptyset\fR \fBpriv_fillset\fR +\fBpriv_freeset\fR \fBpriv_getbyname\fR +\fBpriv_getbynum\fR \fBpriv_getsetbyname\fR +\fBpriv_getsetbynum\fR \fBpriv_gettext\fR +\fBpriv_ineffect\fR \fBpriv_intersect\fR +\fBpriv_inverse\fR \fBpriv_isemptyset\fR +\fBpriv_isequalset\fR \fBpriv_isfullset\fR +\fBpriv_ismember\fR \fBpriv_issubset\fR +\fBpriv_set\fR \fBpriv_set_to_str\fR +\fBpriv_str_to_set\fR \fBpriv_union\fR +\fBprocessor_bind\fR \fBprocessor_info\fR +\fBprofil\fR \fBpselect\fR +\fBpset_assign\fR \fBpset_bind\fR +\fBpset_create\fR \fBpset_destroy\fR +\fBpset_getattr\fR \fBpset_getloadavg\fR +\fBpset_info\fR \fBpset_list\fR +\fBpset_setattr\fR \fBpsiginfo\fR +\fBpsignal\fR \fBpthread_atfork\fR +\fBpthread_attr_destroy\fR \fBpthread_attr_get_np\fR \fBpthread_attr_getdetachstate\fR \fBpthread_attr_getguardsize\fR \fBpthread_attr_getinheritsched\fR \fBpthread_attr_getschedparam\fR \fBpthread_attr_getschedpolicy\fR \fBpthread_attr_getscope\fR @@ -531,44 +514,43 @@ l l . \fBpthread_getconcurrency\fR \fBpthread_getschedparam\fR \fBpthread_getspecific\fR \fBpthread_join\fR \fBpthread_key_create\fR \fBpthread_key_create_once_np\fR -\fBpthread_key_delete\fR -\fBpthread_kill\fR \fBpthread_mutex_consistent\fR -\fBpthread_mutex_destroy\fR \fBpthread_mutex_getprioceiling\fR -\fBpthread_mutex_init\fR \fBpthread_mutex_lock\fR -\fBpthread_mutex_reltimedlock_np\fR \fBpthread_mutex_setprioceiling\fR -\fBpthread_mutex_timedlock\fR \fBpthread_mutex_trylock\fR -\fBpthread_mutex_unlock\fR \fBpthread_mutexattr_destroy\fR -\fBpthread_mutexattr_getprioceiling\fR \fBpthread_mutexattr_getprotocol\fR -\fBpthread_mutexattr_getpshared\fR \fBpthread_mutexattr_getrobust\fR -\fBpthread_mutexattr_gettype\fR \fBpthread_mutexattr_init\fR -\fBpthread_mutexattr_setprioceiling\fR \fBpthread_mutexattr_setprotocol\fR -\fBpthread_mutexattr_setpshared\fR \fBpthread_mutexattr_setrobust\fR -\fBpthread_mutexattr_settype\fR \fBpthread_once\fR -\fBpthread_rwlock_destroy\fR \fBpthread_rwlock_init\fR -\fBpthread_rwlock_rdlock\fR \fBpthread_rwlock_reltimedrdlock_np\fR -\fBpthread_rwlock_reltimedwrlock_np\fR \fBpthread_rwlock_timedrdlock\fR -\fBpthread_rwlock_timedwrlock\fR \fBpthread_rwlock_tryrdlock\fR -\fBpthread_rwlock_trywrlock\fR \fBpthread_rwlock_unlock\fR -\fBpthread_rwlock_wrlock\fR \fBpthread_rwlockattr_destroy\fR -\fBpthread_rwlockattr_getpshared\fR \fBpthread_rwlockattr_init\fR -\fBpthread_rwlockattr_setpshared\fR \fBpthread_self\fR -\fBpthread_setcancelstate\fR \fBpthread_setcanceltype\fR -\fBpthread_setconcurrency\fR \fBpthread_setspecific\fR -\fBpthread_sigmask\fR \fBpthread_setschedparam\fR -\fBpthread_setschedprio\fR \fBpthread_spin_destroy\fR -\fBpthread_spin_init\fR \fBpthread_spin_lock\fR -\fBpthread_spin_trylock\fR \fBpthread_spin_unlock\fR -\fBpthread_testcancel\fR \fBptsname\fR -\fBputacct\fR \fBputc\fR -\fBputc_unlocked\fR \fBputchar\fR -\fBputchar_unlocked\fR \fBputenv\fR -\fBputmsg\fR \fBputpmsg\fR -\fBputpwent\fR \fBputs\fR -\fBputspent\fR \fBpututline\fR -\fBpututxline\fR \fBputw\fR -\fBputwc\fR \fBputwchar\fR -\fBputws\fR \fBpwrite\fR -\fBpwritev\fR +\fBpthread_key_delete\fR \fBpthread_kill\fR +\fBpthread_mutex_consistent\fR \fBpthread_mutex_destroy\fR +\fBpthread_mutex_getprioceiling\fR \fBpthread_mutex_init\fR +\fBpthread_mutex_lock\fR \fBpthread_mutex_reltimedlock_np\fR +\fBpthread_mutex_setprioceiling\fR \fBpthread_mutex_timedlock\fR +\fBpthread_mutex_trylock\fR \fBpthread_mutex_unlock\fR +\fBpthread_mutexattr_destroy\fR \fBpthread_mutexattr_getprioceiling\fR +\fBpthread_mutexattr_getprotocol\fR \fBpthread_mutexattr_getpshared\fR +\fBpthread_mutexattr_getrobust\fR \fBpthread_mutexattr_gettype\fR +\fBpthread_mutexattr_init\fR \fBpthread_mutexattr_setprioceiling\fR +\fBpthread_mutexattr_setprotocol\fR \fBpthread_mutexattr_setpshared\fR +\fBpthread_mutexattr_setrobust\fR \fBpthread_mutexattr_settype\fR +\fBpthread_once\fR \fBpthread_rwlock_destroy\fR +\fBpthread_rwlock_init\fR \fBpthread_rwlock_rdlock\fR +\fBpthread_rwlock_reltimedrdlock_np\fR \fBpthread_rwlock_reltimedwrlock_np\fR +\fBpthread_rwlock_timedrdlock\fR \fBpthread_rwlock_timedwrlock\fR +\fBpthread_rwlock_tryrdlock\fR \fBpthread_rwlock_trywrlock\fR +\fBpthread_rwlock_unlock\fR \fBpthread_rwlock_wrlock\fR +\fBpthread_rwlockattr_destroy\fR \fBpthread_rwlockattr_getpshared\fR +\fBpthread_rwlockattr_init\fR \fBpthread_rwlockattr_setpshared\fR +\fBpthread_self\fR \fBpthread_setcancelstate\fR +\fBpthread_setcanceltype\fR \fBpthread_setconcurrency\fR +\fBpthread_setspecific\fR \fBpthread_sigmask\fR +\fBpthread_setschedparam\fR \fBpthread_setschedprio\fR +\fBpthread_spin_destroy\fR \fBpthread_spin_init\fR +\fBpthread_spin_lock\fR \fBpthread_spin_trylock\fR +\fBpthread_spin_unlock\fR \fBpthread_testcancel\fR +\fBptsname\fR \fBputacct\fR +\fBputc\fR \fBputc_unlocked\fR +\fBputchar\fR \fBputchar_unlocked\fR +\fBputenv\fR \fBputmsg\fR +\fBputpmsg\fR \fBputpwent\fR +\fBputs\fR \fBputspent\fR +\fBpututline\fR \fBpututxline\fR +\fBputw\fR \fBputwc\fR +\fBputwchar\fR \fBputws\fR +\fBpwrite\fR \fBpwritev\fR \fBqeconvert\fR \fBqecvt\fR \fBqfconvert\fR \fBqfcvt\fR \fBqgconvert\fR \fBqgcvt\fR @@ -586,58 +568,56 @@ l l . \fBre_comp\fR \fBre_exec\fR \fBread\fR \fBreaddir\fR \fBreaddir_r\fR \fBreadlink\fR -\fBreadlinkat\fR -\fBreadv\fR \fBrealloc\fR -\fBrealpath\fR \fBreboot\fR -\fBregcmp\fR \fBregcomp\fR -\fBregerror\fR \fBregex\fR -\fBregexec\fR \fBregfree\fR -\fBremove\fR \fBremque\fR -\fBrename\fR \fBrenameat\fR -\fBresetmnttab\fR \fBresolvepath\fR -\fBrewind\fR \fBrewinddir\fR -\fBrindex\fR \fBrmdir\fR -\fBrw_rdlock\fR \fBrw_read_held\fR -\fBrw_tryrdlock\fR \fBrw_trywrlock\fR -\fBrw_unlock\fR \fBrw_write_held\fR -\fBrw_wrlock\fR \fBrwlock_destroy\fR -\fBrwlock_init\fR \fBsbrk\fR -\fBscalb\fR \fBscandir\fR -\fBscanf\fR \fBsched_get_priority_max\fR -\fBsched_get_priority_min\fR \fBsched_getparam\fR -\fBsched_getscheduler\fR \fBsched_rr_get_interval\fR -\fBsched_setparam\fR \fBsched_setscheduler\fR -\fBsched_yield\fR \fBschedctl_exit\fR -\fBschedctl_init\fR \fBschedctl_lookup\fR -\fBschedctl_start\fR \fBschedctl_stop\fR -\fBseconvert\fR \fBseed48\fR -\fBseekdir\fR \fBselect\fR -\fBsem_close\fR \fBsem_destroy\fR -\fBsem_getvalue\fR \fBsem_init\fR -\fBsem_open\fR \fBsem_post\fR -\fBsem_reltimedwait_np\fR \fBsem_timedwait\fR -\fBsem_trywait\fR \fBsem_unlink\fR -\fBsem_wait\fR +\fBreadlinkat\fR \fBreadv\fR +\fBrealloc\fR \fBrealpath\fR +\fBreboot\fR \fBregcmp\fR +\fBregcomp\fR \fBregerror\fR +\fBregex\fR \fBregexec\fR +\fBregfree\fR \fBremove\fR +\fBremque\fR \fBrename\fR +\fBrenameat\fR \fBresetmnttab\fR +\fBresolvepath\fR \fBrewind\fR +\fBrewinddir\fR \fBrindex\fR +\fBrmdir\fR \fBrw_rdlock\fR +\fBrw_read_held\fR \fBrw_tryrdlock\fR +\fBrw_trywrlock\fR \fBrw_unlock\fR +\fBrw_write_held\fR \fBrw_wrlock\fR +\fBrwlock_destroy\fR \fBrwlock_init\fR +\fBsbrk\fR \fBscalb\fR +\fBscandir\fR \fBscanf\fR +\fBsched_get_priority_max\fR \fBsched_get_priority_min\fR +\fBsched_getparam\fR \fBsched_getscheduler\fR +\fBsched_rr_get_interval\fR \fBsched_setparam\fR +\fBsched_setscheduler\fR \fBsched_yield\fR +\fBschedctl_exit\fR \fBschedctl_init\fR +\fBschedctl_lookup\fR \fBschedctl_start\fR +\fBschedctl_stop\fR \fBseconvert\fR +\fBseed48\fR \fBseekdir\fR +\fBselect\fR \fBsem_close\fR +\fBsem_destroy\fR \fBsem_getvalue\fR +\fBsem_init\fR \fBsem_open\fR +\fBsem_post\fR \fBsem_reltimedwait_np\fR +\fBsem_timedwait\fR \fBsem_trywait\fR +\fBsem_unlink\fR \fBsem_wait\fR \fBsema_destroy\fR \fBsema_held\fR \fBsema_init\fR \fBsema_post\fR \fBsema_trywait\fR \fBsema_wait\fR \fBsemctl\fR \fBsemget\fR \fBsemids\fR \fBsemop\fR \fBsemtimedop\fR \fBsetattrat\fR -\fBsetbuf\fR -\fBsetbuffer\fR \fBsetcat\fR -\fBsetcontext\fR \fBsetegid\fR -\fBsetenv\fR \fBseteuid\fR -\fBsetgid\fR \fBsetgrent\fR -\fBsetgroups\fR \fBsethostname\fR -\fBsetitimer\fR \fBsetjmp\fR -\fBsetkey\fR \fBsetlabel\fR -\fBsetlinebuf\fR \fBsetlocale\fR -\fBsetlogmask\fR \fBsetnetgrent\fR -\fBsetpflags\fR \fBsetpgid\fR -\fBsetpgrp\fR \fBsetppriv\fR -\fBsetpriority\fR \fBsetprogname\fR -\fBsetpwent\fR +\fBsetbuf\fR \fBsetbuffer\fR +\fBsetcat\fR \fBsetcontext\fR +\fBsetegid\fR \fBsetenv\fR +\fBseteuid\fR \fBsetgid\fR +\fBsetgrent\fR \fBsetgroups\fR +\fBsethostname\fR \fBsetitimer\fR +\fBsetjmp\fR \fBsetkey\fR +\fBsetlabel\fR \fBsetlinebuf\fR +\fBsetlocale\fR \fBsetlogmask\fR +\fBsetnetgrent\fR \fBsetpflags\fR +\fBsetpgid\fR \fBsetpgrp\fR +\fBsetppriv\fR \fBsetpriority\fR +\fBsetprogname\fR \fBsetpwent\fR \fBsetrctl\fR \fBsetregid\fR \fBsetreuid\fR \fBsetrlimit\fR \fBsetsid\fR \fBsetspent\fR @@ -659,14 +639,13 @@ l l . \fBsiglongjmp\fR \fBsignal\fR \fBsigpause\fR \fBsigpending\fR \fBsigprocmask\fR \fBsigqueue\fR -\fBsigrelse\fR -\fBsigsend\fR \fBsigsendset\fR -\fBsigset\fR \fBsigsetjmp\fR -\fBsigstack\fR \fBsigsuspend\fR -\fBsigtimedwait\fR \fBsigwait\fR -\fBsigwaitinfo\fR \fBsingle_to_decimal\fR -\fBsleep\fR \fBsmt_pause\fR -\fBsnprintf\fR +\fBsigrelse\fR \fBsigsend\fR +\fBsigsendset\fR \fBsigset\fR +\fBsigsetjmp\fR \fBsigstack\fR +\fBsigsuspend\fR \fBsigtimedwait\fR +\fBsigwait\fR \fBsigwaitinfo\fR +\fBsingle_to_decimal\fR \fBsleep\fR +\fBsmt_pause\fR \fBsnprintf\fR \fBsprintf\fR \fBsrand\fR \fBsrand48\fR \fBsrandom\fR \fBsscanf\fR \fBssignal\fR @@ -674,16 +653,15 @@ l l . \fBstack_setbounds\fR \fBstack_violation\fR \fBstat\fR \fBstatfs\fR \fBstatvfs\fR \fBstime\fR -\fBstr2sig\fR -\fBstrcasecmp\fR \fBstrcasecmp_l\fR -\fBstrcat\fR \fBstrchr\fR -\fBstrcmp\fR \fBstrcoll\fR -\fBstrcpy\fR \fBstrcspn\fR -\fBstrdup\fR \fBstrerror\fR -\fBstrerror_l\fR \fBstrerror_r\fR -\fBstrfmon\fR \fBstrfmon_l\fR -\fBstrftime\fR \fBstrftime_l\fR -\fBstring_to_decimal\fR +\fBstr2sig\fR \fBstrcasecmp\fR +\fBstrcasecmp_l\fR \fBstrcat\fR +\fBstrchr\fR \fBstrcmp\fR +\fBstrcoll\fR \fBstrcpy\fR +\fBstrcspn\fR \fBstrdup\fR +\fBstrerror\fR \fBstrerror_l\fR +\fBstrerror_r\fR \fBstrfmon\fR +\fBstrfmon_l\fR \fBstrftime\fR +\fBstrftime_l\fR \fBstring_to_decimal\fR \fBstrlcat\fR \fBstrlcpy\fR \fBstrlen\fR \fBstrncasecmp\fR \fBstrncasecmp_l\fR \fBstrncat\fR @@ -702,23 +680,22 @@ l l . \fBswab\fR \fBswapcontext\fR \fBswapctl\fR \fBswprintf\fR \fBswscanf\fR \fBsymlink\fR -\fBsymlinkat\fR -\fBsync\fR \fBsync_instruction_memory\fR -\fBsysconf\fR \fBsysfs\fR -\fBsysinfo\fR \fBsyslog\fR -\fBsystem\fR \fBtcdrain\fR -\fBtcflow\fR \fBtcflush\fR -\fBtcgetattr\fR \fBtcgetpgrp\fR -\fBtcgetsid\fR \fBtcsendbreak\fR -\fBtcsetattr\fR \fBtcsetpgrp\fR -\fBtdelete\fR \fBtell\fR -\fBtelldir\fR \fBtempnam\fR -\fBtextdomain\fR \fBtfind\fR -\fBthr_continue\fR \fBthr_create\fR -\fBthr_exit\fR \fBthr_getconcurrency\fR -\fBthr_getprio\fR \fBthr_getspecific\fR -\fBthr_join\fR \fBthr_keycreate\fR -\fBthr_keycreate_once\fR +\fBsymlinkat\fR \fBsync\fR +\fBsync_instruction_memory\fR \fBsysconf\fR +\fBsysfs\fR \fBsysinfo\fR +\fBsyslog\fR \fBsystem\fR +\fBtcdrain\fR \fBtcflow\fR +\fBtcflush\fR \fBtcgetattr\fR +\fBtcgetpgrp\fR \fBtcgetsid\fR +\fBtcsendbreak\fR \fBtcsetattr\fR +\fBtcsetpgrp\fR \fBtdelete\fR +\fBtell\fR \fBtelldir\fR +\fBtempnam\fR \fBtextdomain\fR +\fBtfind\fR \fBthr_continue\fR +\fBthr_create\fR \fBthr_exit\fR +\fBthr_getconcurrency\fR \fBthr_getprio\fR +\fBthr_getspecific\fR \fBthr_join\fR +\fBthr_keycreate\fR \fBthr_keycreate_once\fR \fBthr_kill\fR \fBthr_main\fR \fBthr_min_stack\fR \fBthr_self\fR \fBthr_setconcurrency\fR \fBthr_setprio\fR @@ -727,42 +704,40 @@ l l . \fBthr_yield\fR \fBtime\fR \fBtimer_create\fR \fBtimer_delete\fR \fBtimer_getoverrun\fR \fBtimer_gettime\fR -\fBtimer_settime\fR -\fBtimes\fR \fBtimezone\fR -\fBtmpfile\fR \fBtmpnam\fR -\fBtmpnam_r\fR \fBtoascii\fR -\fBtolower\fR \fBtolower_l\fR -\fBtoupper\fR \fBtoupper_l\fR -\fBtowctrans\fR \fBtowctrans_l\fR -\fBtowlower\fR \fBtowlower_l\fR -\fBtowupper\fR \fBtowupper_l\fR -\fBtruncate\fR +\fBtimer_settime\fR \fBtimes\fR +\fBtimezone\fR \fBtmpfile\fR +\fBtmpnam\fR \fBtmpnam_r\fR +\fBtoascii\fR \fBtolower\fR +\fBtolower_l\fR \fBtoupper\fR +\fBtoupper_l\fR \fBtowctrans\fR +\fBtowctrans_l\fR \fBtowlower\fR +\fBtowlower_l\fR \fBtowupper\fR +\fBtowupper_l\fR \fBtruncate\fR \fBtsearch\fR \fBttyname\fR \fBttyname_r\fR \fBttyslot\fR \fBtwalk\fR \fBtzname\fR \fBtzset\fR \fBu8_strcmp\fR \fBu8_textprep_str\fR \fBu8_validate\fR -\fBuadmin\fR -\fBualarm\fR \fBuconv_u16tou32\fR -\fBuconv_u16tou8\fR \fBuconv_u32tou16\fR -\fBuconv_u32tou8\fR \fBuconv_u8tou16\fR -\fBuconv_u8tou32\fR \fBucred_free\fR -\fBucred_get\fR \fBucred_getegid\fR -\fBucred_geteuid\fR \fBucred_getgroups\fR -\fBucred_getpflags\fR \fBucred_getpid\fR -\fBucred_getprivset\fR \fBucred_getprojid\fR -\fBucred_getrgid\fR \fBucred_getruid\fR -\fBucred_getsgid\fR \fBucred_getsuid\fR -\fBucred_getzoneid\fR \fBucred_size\fR -\fBulckpwdf\fR \fBulimit\fR -\fBulltostr\fR \fBumask\fR -\fBumount\fR \fBumount2\fR -\fBuname\fR \fBungetc\fR -\fBungetwc\fR \fBunlink\fR -\fBunlinkat\fR \fBunlockpt\fR -\fBunordered\fR \fBunsetenv\fR -\fBupdwtmp\fR \fBupdwtmpx\fR -\fBuselocale\fR +\fBuadmin\fR \fBualarm\fR +\fBuconv_u16tou32\fR \fBuconv_u16tou8\fR +\fBuconv_u32tou16\fR \fBuconv_u32tou8\fR +\fBuconv_u8tou16\fR \fBuconv_u8tou32\fR +\fBucred_free\fR \fBucred_get\fR +\fBucred_getegid\fR \fBucred_geteuid\fR +\fBucred_getgroups\fR \fBucred_getpflags\fR +\fBucred_getpid\fR \fBucred_getprivset\fR +\fBucred_getprojid\fR \fBucred_getrgid\fR +\fBucred_getruid\fR \fBucred_getsgid\fR +\fBucred_getsuid\fR \fBucred_getzoneid\fR +\fBucred_size\fR \fBulckpwdf\fR +\fBulimit\fR \fBulltostr\fR +\fBumask\fR \fBumount\fR +\fBumount2\fR \fBuname\fR +\fBungetc\fR \fBungetwc\fR +\fBunlink\fR \fBunlinkat\fR +\fBunlockpt\fR \fBunordered\fR +\fBunsetenv\fR \fBupdwtmp\fR +\fBupdwtmpx\fR \fBuselocale\fR \fBusleep\fR \fBustat\fR \fButime\fR \fButimensat\fR \fButimes\fR \fButmpname\fR @@ -787,26 +762,24 @@ l l . \fBwcpcpy\fR \fBwcpncpy\fR \fBwcrtomb\fR \fBwcrtomb_l\fR \fBwcscasecmp\fR \fBwcscasecmp_l\fR -\fBwcscat\fR -\fBwcschr\fR \fBwcscmp\fR -\fBwcscoll\fR \fBwcscoll_l\fR -\fBwcscpy\fR \fBwcscspn\fR -\fBwcsdup\fR \fBwcsftime\fR -\fBwcslen\fR \fBwcsncat\fR -\fBwcsncasecmp\fR \fBwcsncasecmp_l\fR -\fBwcsncmp\fR \fBwcsncpy\fR -\fBwcsnrtombs\fR \fBwcsnrtombs_l\fR -\fBwcspbrk\fR \fBwcsrchr\fR -\fBwcsrtombs\fR \fBwcsrtombs_l\fR -\fBwcsspn\fR +\fBwcscat\fR \fBwcschr\fR +\fBwcscmp\fR \fBwcscoll\fR +\fBwcscoll_l\fR \fBwcscpy\fR +\fBwcscspn\fR \fBwcsdup\fR +\fBwcsftime\fR \fBwcslen\fR +\fBwcsncat\fR \fBwcsncasecmp\fR +\fBwcsncasecmp_l\fR \fBwcsncmp\fR +\fBwcsncpy\fR \fBwcsnrtombs\fR +\fBwcsnrtombs_l\fR \fBwcspbrk\fR +\fBwcsrchr\fR \fBwcsrtombs\fR +\fBwcsrtombs_l\fR \fBwcsspn\fR \fBwcsstr\fR \fBwcstod\fR \fBwcstof\fR \fBwcstoimax\fR \fBwcstok\fR \fBwcstol\fR \fBwcstold\fR \fBwcstoll\fR \fBwcstombs\fR \fBwctombs_l\fR -\fBwcstoul\fR -\fBwcstoull\fR \fBwcstoumax\fR -\fBwcswcs\fR +\fBwcstoul\fR \fBwcstoull\fR +\fBwcstoumax\fR \fBwcswcs\fR \fBwcswidth\fR \fBwcswidth_l\fR \fBwcsxfrm\fR \fBwcsxfrm_l\fR \fBwctob\fR \fBwctob_l\fR diff --git a/usr/src/man/man7d/pts.7d b/usr/src/man/man7d/pts.7d index 19f67addc1..6ac5bbcbd1 100644 --- a/usr/src/man/man7d/pts.7d +++ b/usr/src/man/man7d/pts.7d @@ -1,14 +1,13 @@ '\" te +.\" Copyright 2020 OmniOS Community Edition (OmniOSce) Association. .\" Copyright 1992 Sun Microsystems .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH PTS 7D "Aug 21, 1992" +.TH PTS 7D "Feb 29, 2020" .SH NAME pts \- STREAMS pseudo-tty slave driver .SH DESCRIPTION -.sp -.LP The pseudo-tty subsystem simulates a terminal connection, where the master side represents the terminal and the slave represents the user process's special device end point. In order to use the pseudo-tty subsystem, a node for the @@ -26,9 +25,10 @@ Only one open is allowed on a master device. Multiple opens are allowed on the slave device. After both the master and slave have been opened, the user has two file descriptors which are end points of a full duplex connection composed of two streams automatically connected at the master and slave drivers. The -user may then push modules onto either side of the stream pair. The user needs -to push the \fBptem\fR(7M) and \fBldterm\fR(7M) modules onto the slave side of -the pseudo-terminal subsystem to get terminal semantics. +user may then push modules onto either side of the stream pair. Unless compiled +in XPG4v2 mode (see below), the consumer needs to push the \fBptem\fR(7M) and +\fBldterm\fR(7M) modules onto the slave side of the pseudo-terminal subsystem +to get terminal semantics. .sp .LP The master and slave drivers pass all messages to their adjacent queues. Only @@ -48,14 +48,23 @@ device is not closed, the pseudo-tty subsystem will be available to another user to open the slave device. Since 0-length messages are used to indicate that the process on the slave side has closed and should be interpreted that way by the process on the master side, applications on the slave side should -not write 0-length messages. If that occurs, the write returns 0, and the -0-length message is discarded by the \fBptem\fR module. +not write 0-length messages. Unless the application is compiled in XPG4v2 mode +(see below) then any 0-length messages written on the slave side will be +discarded by the \fBptem\fR module. .sp .LP The standard STREAMS system calls can access the pseudo-tty devices. The slave devices support the \fBO_NDELAY\fR and \fBO_NONBLOCK\fR flags. -.SH EXAMPLES +.SH XPG4v2 MODE +XPG4v2 requires that open of a slave pseudo terminal device provides the +process with an interface that is identical to the terminal interface (without +having to explicitly push any modules to achieve this). It also requires that +0-length messages written on the slave side will be propagated to the master. .sp +Experience has shown, however, that most software does not expect slave pty +devices to operate in this manner and therefore this XPG4v2-compliant +behaviour is only enabled in XPG4v2/SUS (see \fBstandards\fR(5)) mode. +.SH EXAMPLES .in +2 .nf int fdm fds; @@ -73,7 +82,6 @@ ioctl(fds, I_PUSH, "ldterm"); /* push ldterm*/ .in -2 .SH FILES -.sp .ne 2 .na \fB\fB/dev/ptmx\fR\fR @@ -92,10 +100,8 @@ slave devices (M = 0 -> N-1) .RE .SH SEE ALSO -.sp -.LP \fBgrantpt\fR(3C), \fBptsname\fR(3C), \fBunlockpt\fR(3C), \fBldterm\fR(7M), -\fBptm\fR(7D), \fBptem\fR(7M) +\fBptm\fR(7D), \fBptem\fR(7M), \fBstandards\fR(5) .sp .LP \fISTREAMS Programming Guide\fR diff --git a/usr/src/uts/common/io/ldterm.c b/usr/src/uts/common/io/ldterm.c index 97a9c1a478..46669ace0c 100644 --- a/usr/src/uts/common/io/ldterm.c +++ b/usr/src/uts/common/io/ldterm.c @@ -22,7 +22,7 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright (c) 2018, Joyent, Inc. - * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -4087,7 +4087,8 @@ ldterm_dosig(queue_t *q, int sig, uchar_t c, int mtype, int mode) if (c != '\0') { if ((tp->t_echomp = allocb(4, BPRI_HI)) != NULL) { - if (ldterm_echo(c, WR(q), 4, tp) > 0) + if (ldterm_echo(c, WR(q), 4, tp) > 0 || + (tp->t_state & TS_ISPTSTTY)) putnext(WR(q), tp->t_echomp); else freemsg(tp->t_echomp); diff --git a/usr/src/uts/common/io/ptm.c b/usr/src/uts/common/io/ptm.c index 5904629295..472cbf6936 100644 --- a/usr/src/uts/common/io/ptm.c +++ b/usr/src/uts/common/io/ptm.c @@ -24,7 +24,9 @@ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ - +/* + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + */ /* * Pseudo Terminal Master Driver. @@ -521,6 +523,13 @@ ptmwput(queue_t *qp, mblk_t *mp) DBG(("ack the UNLKPT/ISPTM\n")); miocack(qp, mp, 0, 0); break; + case PTSSTTY: + mutex_enter(&ptmp->pt_lock); + ptmp->pt_state |= PTSTTY; + mutex_exit(&ptmp->pt_lock); + DBG(("ack PTSSTTY\n")); + miocack(qp, mp, 0, 0); + break; case ZONEPT: { zoneid_t z; diff --git a/usr/src/uts/common/io/pts.c b/usr/src/uts/common/io/pts.c index d67beb255a..ff2d91f566 100644 --- a/usr/src/uts/common/io/pts.c +++ b/usr/src/uts/common/io/pts.c @@ -25,7 +25,9 @@ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ - +/* + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + */ /* * Pseudo Terminal Slave Driver. @@ -106,6 +108,7 @@ #include #include #include +#include #include #include #include @@ -337,7 +340,6 @@ ptsopen( DDBGP("ptsopen: p = %p\n", (uintptr_t)ptsp); DDBG("ptsopen: state = %x\n", ptsp->pt_state); - ASSERT(ptsp->pt_minor == dminor); if ((ptsp->pt_state & PTLOCK) || !(ptsp->pt_state & PTMOPEN)) { @@ -347,7 +349,7 @@ ptsopen( } /* - * if already, open simply return... + * if already open, simply return... */ if (ptsp->pt_state & PTSOPEN) { ASSERT(rqp->q_ptr == ptsp); @@ -386,6 +388,9 @@ ptsopen( mutex_exit(&ptsp->pt_lock); mutex_exit(&ptms_lock); + if (ptsp->pt_state & PTSTTY) + STREAM(rqp)->sd_flag |= STRXPG4TTY; + qprocson(rqp); /* @@ -416,8 +421,6 @@ ptsopen( return (0); } - - /* * Find the address to private data identifying the slave's write * queue. Send a 0-length msg up the slave's read queue to designate diff --git a/usr/src/uts/common/os/streamio.c b/usr/src/uts/common/os/streamio.c index 102c803f5f..3a5c1ecd19 100644 --- a/usr/src/uts/common/os/streamio.c +++ b/usr/src/uts/common/os/streamio.c @@ -25,7 +25,7 @@ /* * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2017 Joyent, Inc. - * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ #include @@ -78,6 +78,7 @@ #include #include #include +#include #include /* @@ -231,6 +232,50 @@ push_mod(queue_t *qp, dev_t *devp, struct stdata *stp, const char *name, return (0); } +static int +xpg4_fixup(queue_t *qp, dev_t *devp, struct stdata *stp, cred_t *crp) +{ + static const char *ptsmods[] = { + "ptem", "ldterm", "ttcompat" + }; + dev_t dummydev = *devp; + struct strioctl strioc; + zoneid_t zoneid; + int32_t rval; + uint_t i; + + /* + * Push modules required for the slave PTY to have terminal + * semantics out of the box; this is required by XPG4v2. + * These three modules are flagged as single-instance so that + * the system will never end up with duplicate copies pushed + * onto a stream. + */ + + zoneid = crgetzoneid(crp); + for (i = 0; i < ARRAY_SIZE(ptsmods); i++) { + int error; + + error = push_mod(qp, &dummydev, stp, ptsmods[i], 0, + crp, zoneid); + if (error != 0) + return (error); + } + + /* + * Send PTSSTTY down the stream + */ + + strioc.ic_cmd = PTSSTTY; + strioc.ic_timout = 0; + strioc.ic_len = 0; + strioc.ic_dp = NULL; + + (void) strdoioctl(stp, &strioc, FNATIVE, K_TO_K, crp, &rval); + + return (0); +} + /* * Open a stream device. */ @@ -549,10 +594,15 @@ retryap: opendone: + if (error == 0 && + (stp->sd_flag & (STRISTTY|STRXPG4TTY)) == (STRISTTY|STRXPG4TTY)) { + error = xpg4_fixup(qp, devp, stp, crp); + } + /* * let specfs know that open failed part way through */ - if (error) { + if (error != 0) { mutex_enter(&stp->sd_lock); stp->sd_flag |= STREOPENFAIL; mutex_exit(&stp->sd_lock); diff --git a/usr/src/uts/common/sys/strsubr.h b/usr/src/uts/common/sys/strsubr.h index 306a2f6b29..43477446c2 100644 --- a/usr/src/uts/common/sys/strsubr.h +++ b/usr/src/uts/common/sys/strsubr.h @@ -28,7 +28,7 @@ */ /* - * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ #ifndef _SYS_STRSUBR_H @@ -288,7 +288,7 @@ typedef struct stdata { #define SNDMREAD 0x00008000 /* used for read notification */ #define OLDNDELAY 0x00010000 /* use old TTY semantics for */ /* NDELAY reads and writes */ - /* 0x00020000 unused */ +#define STRXPG4TTY 0x00020000 /* Use XPG4 TTY semantics */ /* 0x00040000 unused */ #define STRTOSTOP 0x00080000 /* block background writes */ #define STRCMDWAIT 0x00100000 /* someone is doing an _I_CMD */ -- cgit v1.2.3