Friday, October 21, 2016

AI: Distro Constructor and a Custom Script

When building your own AI images with distro_const it is useful sometimes to add a custom script to modify the resulting image. This is easily achievable by adding a custom script to the xml manifest provided to distro_cons.

For example, to change the default password for user jack, add the following checkpoint to the xml file, just before pre-pkg-img-mode checkpoint. 

<!--
  Set password to user jack, should match root password
  (if hash contains slashed they need to be backslashed)
-->
      <checkpoint name="lock-jack-account"
         desc="Lock the jack account from login"
         mod_path="solaris_install/distro_const/checkpoints/custom_script"
         checkpoint_class="CustomScript">
         <args>/usr/bin/gsed -i -e 's/jack:.[^:]*:/jack:XXXXXX:/g' 
                             {PKG_IMAGE_PATH}/etc/shadow
         </args>
      </checkpoint>

Tuesday, October 11, 2016

Requiring both GSSAPI and OTP

Darren Moffat blogged about how to force both GSSAPI (or pubkey) and OTP on Solaris in OpenSSH. This works, although is not entirely obvious how to set it up at first.

Friday, July 01, 2016

SPARC S7

Oracle released new SPARC S7 CPU and SPARC S7-2 and S7-2L servers. This is really interesting SPARC CPU if you need low-end servers, the first one in many, many years which can compete with x86 both in performance and price. It has some unique features as well.

See launch video.

Various articles on S7:

TheNextPlatform
The Register
PCWorld
ComputerWorld

Also see some benchmarks already published:

SPECjbb2015
SPECjEnterprise2010
Database: S7 vs x86
Yahoo Cloud Serving Benchmark


Friday, May 20, 2016

Adjusting SO_RCVBUF of a running process

Recently I was looking into how to increase SO_RCVBUF size for a given socket in a running process, without having to restart it. This could be useful, if an application can't be restarted anytime soon, yet there are drops observed due to too low receive buffer set, or perhaps a given application doesn't even allow for the receive buffer to be specified and has a hard-coded value. In my case, an application does allow for the buffer to be specified, but it only sets it on startup and I couldn't restart it.

Solaris (nor Linux AFAIK) does not provide a tool to easily adjust the buffer for a socket in a running process, so I looked if I could do it via libproc. The answer is yes, and it is pretty straightforward.

I quickly wrote a small C program which changes the SO_RCVBUF size for a given pid and file descriptor number. Let's see an example on how to use it.

There is a process with pid 893 listening on port UDP/32623 with the SO_RCVBUG currently set to 128104:

# pfiles 893
893:    /usr/local/bin/test-daemon
  Current rlimit: 256 file descriptors
...
   4: S_IFSOCK mode:0666 dev:574,0 ino:43685 uid:0 gid:0 size:0
      O_RDWR|O_NONBLOCK FD_CLOEXEC
      SOCK_STREAM
      SO_REUSEADDR,SO_SNDBUF(49152),SO_RCVBUF(128104)
      sockname: AF_INET 0.0.0.0  port: 32623
      congestion control: newreno
...

Let's change the SO_RCVBUG to a higher value:

# ./pr_setsockopt 893 4 500000
Current SO_RCVBUG is 128104
New SO_RCVBUG is 500088

# pfiles 893
...
   4: S_IFSOCK mode:0666 dev:574,0 ino:43685 uid:0 gid:0 size:0
      O_RDWR|O_NONBLOCK FD_CLOEXEC
      SOCK_STREAM
      SO_REUSEADDR,SO_SNDBUF(49152),SO_RCVBUF(500088)
      sockname: AF_INET 0.0.0.0  port: 32623
      congestion control: newreno
...

The code is very similar to the one I wrote last time. However, as there is no pr_setsockopt() wrapper function, I wrote one based on how the other pr_* functions are implemented, specifically pr_getsockopt(). The trick is that there is Psyscall() function available, which allows you to call any syscall from the target process, so all that is required is to use it to call SYS_setsockopt.

As the source code for Solaris is no longer publicly available, I used Illumos source code. The program was tested only on Solaris 11 x86, although it probably works fine on Solaris 10 and Illumos, and should work on SPARC as well.

It is a quick "hack", with no safeguards, no proper argument parsing, etc.
Use it at your own risk.

// gcc -m64 -lproc -o pr_setsockopt pr_setsockopt.c

#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <libproc.h>


pr_setsockopt(struct ps_prochandle *Pr, int sock, int level, int optname, void *optval, int optlen) {
  sysret_t rval;  /* return value from getsockopt() */
  argdes_t argd[5]; /* arg descriptors for getsockopt() */
  argdes_t *adp;
  int error;

  if (Pr == NULL)  /* no subject process */
    return (_so_setsockopt(sock, level, optname, optval, optlen));

  adp = &argd[0];  /* sock argument */
  adp->arg_value = sock;
  adp->arg_object = NULL;
  adp->arg_type = AT_BYVAL;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = 0;

  adp++;   /* level argument */
  adp->arg_value = level;
  adp->arg_object = NULL;
  adp->arg_type = AT_BYVAL;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = 0;

  adp++;   /* optname argument */
  adp->arg_value = optname;
  adp->arg_object = NULL;
  adp->arg_type = AT_BYVAL;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = 0;

  adp++;   /* optval argument */
  adp->arg_value = 0;
  adp->arg_object = optval;
  adp->arg_type = AT_BYREF;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = optlen == NULL ? 0 : optlen;

  adp++;   /* optlen argument */
  adp->arg_value = optlen;
  adp->arg_object = NULL;
  adp->arg_type = AT_BYVAL;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = 0;

  error = Psyscall(Pr, &rval, SYS_setsockopt, 5, &argd[0]);

  if (error) {
    errno = (error > 0)? error : ENOSYS;
    return (-1);
  }
  return (0);
}


int main(int argc, char **argv) {
  pid_t pid;
  int fd;
  int perr;
  static struct ps_prochandle *Pr;

  pid = atop(argv[1]);
  fd = atoi(argv[2]);

  if((Pr = Pgrab(pid, PGRAB_NOSTOP, &perr)) == NULL) {
    printf("Pgrab() failed: %s\n", Pgrab_error(perr));
    exit(1);
  }

  int rcvbuf = 0;
  int rcvbuf_size = sizeof(rcvbuf);
  if(pr_getsockopt(Pr, fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &rcvbuf_size)) {
    perror("pr_getsockopt() failed");
    Prelease(Pr, 0);
    exit(1);
  }

  printf("Current SO_RCVBUF is %d\n", rcvbuf);

  rcvbuf = atoi(argv[3]);
  if(pr_setsockopt(Pr, fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, rcvbuf_size)) {
    perror("pr_setsockopt() failed");
    Prelease(Pr, 0);
    exit(1);
  }

  if(pr_getsockopt(Pr, fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &rcvbuf_size)) {
    perror("pr_getsockopt() failed");
    Prelease(Pr, 0);
    exit(1);
  }

  printf("New SO_RCVBUF is %d\n", rcvbuf);

  Prelease(Pr, 0);
  Pr = NULL;

  exit(0);  
}

Wednesday, March 02, 2016

Full command line returned by ps

ps command can now show full command line on Solaris 11 as well. Thank you Casper.
For more details see here.

Sunday, August 30, 2015

Remote Management of ZFS servers with Puppet and RAD

Manuel Zach blogs about how to use Puppet and the new Solaris RAD's REST interface introduced in Solaris 11.3. Solaris RAD is really interesting if you want to manage your servers via a programmatic interface.

Friday, August 07, 2015

Kernel Zones - Adding Local Disks

It is possible to add a disk drive to a kernel zone by specifying its physical location intead of CTD.

add device
set storage=dev:chassis/SYS/HDD23/disk
set id=1
end
This is very nice on servers like x5-2l with pass-thru controller when all 26 local disks are visible like this.

Friday, July 10, 2015

Solaris 11.3 Beta

Solaris 11.3 Beta is available now. There are many interesting new features and lots of improvements.
Some of them have already been available if you had access to Solaris Support repository, but if not now you can play with ZFS persistent l2arc, which can also hold compressed blocks, or ZFS/lz4 compression, or perhaps you fancy a new (to Solaris) OpenBSD Packet Filter, or... see What's New for more details on all the new features.

Also see a collection of blog posts which have more technical details about the new features.
New batch of blogs about the new update.

Friday, June 12, 2015