OpenSolaris: Zonas

Introducción

Debemos imaginar una zona de OpenSolaris como un contenedor de procesos, es decir la zona es una jaula cuyo contenido no puede ver lo que hay fuera de ella. Para que los procesos puedan ejecutarse el kernel debe proporcionar una serie de recursos a dicha zona, como pueden ser acceso a discos, interfaces de red, etc. Dichos recursos no pueden ser compartidos entre zonas.

La excepción es la zona global con id 0, esta se crea cuando arranca el sistema y tiene asociado todos los recursos sin restricciones de privilegios. Incluso en los sistemas que no se ha definido ninguna zona existe una zona global.

Cada zona esta identificada por un nombre y un id, el nombre global y el id 0 está reservados para la zona global.

Notas sobre el kernel

En nuestro sistema solo tenemos un Kernel ejecutándose, los procesos de las distintas zonas se ejecutan todos en el mismo que, lógicamente es el que se inicia al arrancar la zona global.

Esto tiene grandes beneficios a nivel de performance, especialmente si el diseño de las zonas ha sido bien pensado.

  • Las páginas de texto (el código de los ejecutables y librerías) que ha cargado en memoria una zona son compartidas con las demás.
  • La caché de nombres de directorios del sistema (DNLC) también es compartida.
  • Las tareas que periódicamente se ejecutan en el kernel (p.ej. todas las de la callout table) no se duplican por cada zona.

Teniendo en cuenta lo anterior interesa, desde el punto de vista de la performance, que las distintas zonas sean los mas parecidas posible y compartan el mayor número de directorios posibles.

P. ej. mientras que levantar el sistema consume en mi equipo 339 megas de la memoria física, arrancar una zona adicional consume solo 79 mb.

####sistema solo con la zona global bash-3.00# mdb -k Loading modules: [ unix genunix specfs dtrace uppc pcplusmp scsi_vhci ufs ip hook neti sctp arp usba fctl nca lofs mpt audiosup zfs random cpc crypto fcip nsctl ptm sppp ipc ] > ::memstat Page Summary Pages MB %Tot ------------ ---------------- ---------------- ---- Kernel 15066 58 12% Anon 52276 204 41% Exec and libs 11141 43 9% Page cache 5927 23 5% Free (cachelist) 24358 95 19% Free (freelist) 20142 78 16% Total 128910 503 Physical 128909 503 ###iniciamos una nueva zona > ::memstat Page Summary Pages MB %Tot ------------ ---------------- ---------------- ---- Kernel 17944 70 14% Anon 69002 269 54% Exec and libs 11305 44 9% Page cache 6139 23 5% Free (cachelist) 18639 72 14% Free (freelist) 5881 22 5% Total 128910 503 Physical 128909 503 >

Notas sobre la seguridad

Si bien ejecutar todos los hilos en el mismo kernel es un beneficio para la performance también supone un reto de cara a la seguridad. Es crítico para la integridad del sistema que los procesos que se ejecutan en una zona estén completamente aislados del resto. Esto se consigue asignando un set de privilegios especifico para los procesos les permite interectuar únicamente con los de su misma zona.

bash-3.00# ppriv -S 11227 11227: bash flags = E: zone I: basic P: zone L: zone

Como pequeño ejemplo prático podemos comprobar como desde la zona global vemos los pids de las demás y no así a viceversa. En ambos casos el id del usuario es 0 (root).

#ps dentro de la zona test bash-3.00# id uid=0(root) gid=0(root) bash-3.00# uname -a SunOS test 5.11 snv_70b i86pc i386 i86pc bash-3.00# ps PID TTY TIME CMD 11227 console 0:01 bash 29665 console 0:02 sh 26806 console 0:00 ps #ps desde la zona global con un grep para ver el proceso bash de la zona test bash-3.00# id uid=0(root) gid=0(root) bash-3.00# ps -ef | grep 11227 root 11227 29665 1 Jan 18 zoneconsole 0:01 bash root 26809 555 1 09:45:14 pts/2 0:00 grep 11227 #ps desde la zona global bash-3.00# ps PID TTY TIME CMD 555 pts/2 0:03 bash 551 pts/2 0:00 sh 26812 pts/2 0:00 ps #ps desde la zona test buscando el pid del bash de la zona global bash-3.00# ps -ef | grep 555 | grep -v grep bash-3.00#

A parte de lo anterior existen algunas tareas que no están permitidas ejecutarse dentro de una zona

  • Modificar interfaces de red o tablas de rutas
  • Acceder al dispositivo /dev/kmem
  • Rebotar o apagar todo el sistema
  • Cargar módulos personalizados del kernel..

Procesos que gestionan una Zona

Existen dos nuevos procesos por cada zona no global que tenemos en el sistema para gestionar los recursos de ellas:

El primero es el zoneadmd, Sus tareas son las siguientes:

  • Crear las estructuras del kernel necesarias y un proceso zsched.
  • Configurar el control a los recursos de dicha zona (como pools de CPU, memoria o privilegios).
  • Configurar los dispositivos la zona con el comando devfsadmd.
  • Crea y destruye las interfaces de red virtuales.
  • Montar los filesystems.
  • Proporciona un servidor de consola para el comando zconsole.
  • Ejecuta el proceso init de la zona.
  • Proporciona un Door Server, los clientes como el zoneadm o el propio kernel se conectan a el para enviar msj de cambio de estado a la zona como halt, reboot, ...

Hay una completa descripción de este proceso en el fichero zoneadmd.c del código fuente.

El otro proceso es el zsched, sus tareas son:

  • Es el padre de todos los threads del kernel de su zona.
  • Lanza el proceso init de la zona cuando arranca.

Ciclo de vida de una zona

Estos son los estados (a nivel de kernel) en los que se puede encontrar una zona, ordenados por el flujo natural de arranque a parada.

ZONE_IS_UNINITIALIZED: la zona se ha añadido a la lista de zonas activas pero aun no es accesible.

ZONE_IS_READY: el proceso zsched esta preparado.

ZONE_IS_BOOTING: es un estado de transición el proceso zsched esta tratando de lanzar el init de la zona.

ZONE_IS_RUNNING: zsched a lanzado correctamente el init, la zona esta lista para trabajar. Permanece en este estado hasta que se le haga un shutdown.

ZONE_IS_SHUTTING_DOWN: se ha ejecutado la llamada zone_shutdown(), el sistema esta matando todos los procesos dentro de la zona.

ZONE_IS_EMPTY: no quedan mas procesos de esta zona ejecutándose.

ZONE_IS_DOWN: todos los threads del kernel relacionados con la zona han terminado.

La estructura zone_t

Por cada zona existente en el sistema hay una estructura zone_t en el kernel, en ella tenemos información acerca del estado y configuración de esta. Podemos ver su definición en el fichero zone.h de nuestro sistema.

typedef struct zone { /* * zone_name is never modified once set. */ char *zone_name; /* zone's configuration name */ /* * zone_nodename and zone_domain are never freed once allocated. */ char *zone_nodename; /* utsname.nodename equivalent */ char *zone_domain; /* srpc_domain equivalent */ /* * zone_lock protects the following fields of a zone_t: * zone_ref * zone_cred_ref * zone_ntasks * zone_flags * zone_zsd */ kmutex_t zone_lock; /* [...]

Dentro de ella encontramos los parámetros con los que hemos configurado la zona, entre ellos los que limitan el consumo de ella como por ejemplo el máximo de memoria que puede consumir, el número de semáforos, etc. Vamos hacer un breve repaso a los mas destacados:

*zone_name; /* nombre de la zona */ zoneid_t zone_id; /* ID de la zona */ rctl_qty_t zone_locked_mem_ctl; /* límite máximo de memoria*/ rctl_qty_t zone_max_swap_ctl; /* límite máximo de swap */ [...]

También hay información de la zona, como por ejemplo:

char *zone_rootpath; /* path de la raiz de la zona */ zone_status_t zone_status; /* en que estado esta actualmente la zona*/ rctl_qty_t zone_nlwps; /* número de hilos ejecutándose */ [...]

Podemos acceder fácilmente a ella usando mdb:

bash-3.00# mdb -k Loading modules: [ unix genunix specfs dtrace uppc pcplusmp scsi_vhci ufs ip hook neti sctp arp usba fctl nca lofs mpt audiosup zfs random sppp crypto ptm md nfs cpc fcip fcp logindmux nsctl sdbc sv ii rdc ] > ::walk zone fec7f028 d5072b40 d884ac40 > ::walk zone fec7f028 d5072b40 d884ac40 > d5072b40 ::zone ADDR ID NAME PATH d5072b40 1 linux /zone/root/ > d884ac40 ::zone ADDR ID NAME PATH d884ac40 3 test /zone_OS/root/ > d884ac40 ::print zone_t { zone_name = 0xd7ce69c0 "test" zone_nodename = 0xd86e5400 "test" zone_domain = 0xd86e57c0 "" zone_lock = { _opaque = [ 0, 0 ] } zone_linkage = { list_next = zone_active+8 list_prev = 0xd5072b54 } zone_id = 0x3 zone_ref = 0x13 zone_cred_ref = 0x1e zone_rootvp = 0xd5074240 zone_rootpath = 0xd884ed10 "/zone_OS/root/" zone_flags = 0 zone_status = 3 (ZONE_IS_RUNNING) zone_ntasks = 0x11 zone_nlwps_lock = { _opaque = [ 0, 0 ] } [...]

Creative Commons License
El contenido de esta web está bajo una licencia de Creative Commons.