frameio_t man page on SmartOS

Man page or keyword search:  
man Server   16655 pages
apropos Keyword Search (all sections)
Output format
SmartOS logo
[printable version]

VND_FRAMEIO_READ(3VND)					VND_FRAMEIO_READ(3VND)

NAME
       vnd_frameio_read,  vnd_frameio_write  -	perform	 framed	 I/O  to a vnd
       device

SYNOPSIS
       cc [ flag... ] file... -lvnd [ library... ]
       #include <libvnd.h>

       int vnd_frameio_read(vnd_handle_t *vhp, frameio_t *fiop);

       int vnd_frameio_write(vnd_handle_t *vhp, frameio_t *fiop);

DESCRIPTION
       Framed I/O is a general means to manipulate  data  that	is  inherently
       framed,	meaning	 that  there is a maximum frame size, but the data may
       often be less than that size. As an example, an Ethernet	 device's  MTU
       describes  the  maximum frame size, but the size of an individual frame
       is often much less. You can read a single frame at a time, or  you  can
       read multiple frames in a single call.

       In  addition, framed I/O allows the consumer to break individual frames
       into a series of vectors. This is analogous to the use of an  iovec(9S)
       with readv(2) and writev(2).

       vnd_frameio_read	 performs  a framed I/O read of the device represented
       by the handle  vhp,  with  the  framed  I/O  data  described  by	 fiop.
       vnd_frameio_write  works	 in the same manner, except performing a write
       instead of a read.

       The basic vector component of the frameio_t  is	the  framevec_t.  Each
       framevec_t  represents  a  single  vector  entry.  An array of these is
       present in the frameio_t. The framevec_t structure  has	the  following
       members:

	 void	   *fv_buf	  /* data buffer */
	 size_t	   fv_buflen;	  /* total size of buffer */
	 size_t	   fv_actlen;	  /* amount of buffer consumed */

       The  fv_buf  member points to a buffer which contains the data for this
       individual vector. When reading, data is	 consumed  from	 fv_buf.  When
       writing, data is written into fv_buf.

       The  fv_buflen  should indicate the total amount of data that is in the
       buffer. When reading, it indicates the size of the buffer. It  must  be
       set prior to calling vnd_frameio_read(). When writing, it indicates the
       amount of data that is valid in the buffer.

       The fv_actlen is a read-only member. It is set on successful return  of
       the  functions vnd_frameio_read and vnd_frameio_write. When reading, it
       is updated with the amount of data that	was  read  into	 fv_buf.  When
       writing, it is instead updated with the amount of data from fv_buf that
       was actually consumed. Generally when writing data, a  framevec_t  will
       either be entirely consumed or it will not be consumed at all.

       A  series of framevec_t's is encapsulated in a frameio_t. The frameio_t
       structure has the following members:

	 uint_t		fio_version;   /* current version */
	 uint_t		fio_nvpf;      /* number of vectors in one frame */
	 uint_t		fio_nvecs;     /* The total number of vectors */
	 framevec_t	fio_vecs[];    /* vectors */

       The fio_version member represents the current version of the frameio_t.
       The  fio_version	 should	 be  set to the macro FRAMEIO_CURRENT_VERSION,
       which is currently 1.

       The members fio_nvpf and fio_nvecs describe the number of  frames  that
       exist. fio_nvecs describes the total number of vectors that are present
       in fio_vecs.  The upper bound on this is described by FRAMEIO_NVECS_MAX
       which  is  currently  32.  fio_nvpf describe the number of vectors that
       should be used to make up each frame. By setting fio_vecs to be an even
       multiple	 of fio_nvpf, multiple frames can be read or written in a sin‐
       gle call.

       After a call to	vnd_frameio_read  or  vnd_frameio_write	 fio_nvecs  is
       updated with total number of vectors read or written to. This value can
       be divided by fio_nvpf to determine the total  number  of  frames  that
       were written or read.

       Each  frame can be broken down into a series of multiple vectors. As an
       example, someone might want to break Ethernet frames into  mac  headers
       and  payloads.  The  value of fio_nvpf would be set to two, to indicate
       that a single frame consists of two different  vector  components.  The
       member  fio_nvecs  describes  the  total number of frames. As such, the
       value of fio_vecs divided by fio_nvpf describes	the  total  number  of
       frames  that can be consumed in one call. As a result of this, fio_nvpf
       must evenly divide fio_vecs. If fio_nvpf is set to two and fio_nvecs is
       set  to ten, then a total of five frames can be processed at once, each
       frame being broken down into two different vector components.

       A given frame will never overflow the number of	vectors	 described  by
       fio_nvpf.  Consider  the	 case where each vector component has a buffer
       sized to 1518 bytes, fio_nvpf is set to one, and fio_nvecs  is  set  to
       three. If a call to vnd_frameio_read is made and four 500 byte Ethernet
       frames come in, then each frame will be mapped to a single vector.  The
       500    bytes    will   be   copied   into   fio_nvecs[i]->fio_buf   and
       fio_nvecs[i]->fio_actlen will be set  to	 500.  To  contrast  this,  if
       readv(2)	 had  been  called, the first three frames would all be in the
       first iov and the fourth frame's first eight  bytes  would  be  in  the
       first iov and the remaining in the second.

       The  user  must properly initialize fio_nvecs framevec_t's worth of the
       fio_vecs array. When multiple vectors comprise a frame, fv_buflen  data
       is consumed before moving onto the next vector. Consider the case where
       the user wants to break a vector into three different components, an 18
       byte  vector  for an Ethernet VLAN header, a 20 byte vector for an IPv4
       header, and a third 1500 byte vector for the remaining  payload.	 If  a
       frame  was  received  that  only	 had 30 bytes, then the first 18 bytes
       would fill up the first vector, the remaining 12 bytes  would  fill  up
       the IPv4 header. If instead a 524 byte frame came in, then the first 18
       bytes would be placed in the first vector, the next 24 bytes  would  be
       placed in the next vector, and the remaining 500 bytes in the third.

       The  functions  vnd_frameio_read	 and vnd_frameio_write operate in both
       blocking and non-blocking mode. If either O_NONBLOCK or	O_NDELAY  have
       been set on the file descriptor, then the I/O will behave in non-block‐
       ing mode. When in non-blocking mode,  if	 no  data  is  available  when
       vnd_frameio_read	 is called, EAGAIN is returned. When vnd_frameio_write
       is called in non-blocking mode, if sufficient buffer space to hold  all
       of  the	output	frames	is  not available, then vnd_frameio_write will
       return EAGAIN. To know when the given vnd device has sufficient	space,
       the  device fires POLLIN/POLLRDNORM when data is available for read and
       POLLOUT/POLLRDOUT when space in the buffer has  opened  up  for	write.
       These  events can be watched for through port_associate(3C) and similar
       routines with a file descriptor returned from vnd_polfd(3VND).

       When non-blocking mode is  disabled,  calls  to	vnd_frameio_read  will
       block   until   some   amount   of   data   is	available.   Calls  to
       vnd_frameio_write will block until sufficient buffer  space  is	avail‐
       able.

       Similar to read(2) and write(2), vnd_frameio_read and vnd_frameio_write
       make no guarantees about the ordering of	 data  when  multiple  threads
       simultaneously  call  the  interface.  While  the  data	itself will be
       atomic, the ordering of multiple simultaneous calls is not defined.

RETURN VALUES
       The vnd_frameio_read function  returns  zero  on	 success.  The	member
       fio_nvecs  of fiop is updated with the total number of vectors that had
       data read into them. Each  updated  framevec_t  will  have  the	buffer
       pointed to by fv_buf filled in with data, and fv_actlen will be updated
       with the amount of valid data in fv_buf.

       The vnd_frameio_write function returns  zero  on	 success.  The	member
       fio_nvecs of fiop is updated with the total number of vectors that were
       written out to the underlying datalink. The fv_actlen of each vector is
       updated	to indicate the amount of data that was written from that buf‐
       fer.

       On failure, both vnd_frameio_read and vnd_frameio_write return -1.  The
       vnd   and   system   error   numbers  are  updated  and	available  via
       vnd_errno(3VND) and vnd_syserrno(3VND). See ERRORS below for a list  of
       errors and their meaning.

ERRORS
       The functions vnd_frameio_read and vnd_frameio_write always set the vnd
       error to VND_E_SYS. The following system errors will be encountered:

       EAGAIN
		 Insufficient system memory was available for the operation.

		 Non-blocking  mode  was  enabled  and	during	the  call   to
		 vnd_frameio_read,  no	data  was available. Non-blocking mode
		 was enabled and during the call to vnd_frameio_write,	insuf‐
		 ficient buffer space was available.

       ENXIO
		 The  vnd  device referred to by vhp is not currently attached
		 to an underlying data link and cannot send data.

       EFAULT
		 The fiop argument points to an illegal address or the	fv_buf
		 members  of  the framevec_t's associated with the fiop member
		 fio_vecs point to illegal addresses.

       EINVAL
		 The fio_version member of fiop was  unknown,  the  number  of
		 vectors  specified  by	 fio_nvecs  is	zero  or  greater than
		 FRAMEIO_NVECS_MAX, fio_nvpf equals  zero,  fio_nvecs  is  not
		 evenly	 divisible  by fio_nvpf, or a buffer in fio_vecs[] has
		 set fv_buf or fv_buflen to zero.

       EINTR
		 A   signal   was   caught    during	vnd_frameio_read    or
		 vnd_frameio_write, and no data was transferred.

       EOVERFLOW
		 During	 vnd_frameio_read,  the	 size  of a frame specified by
		 fiop->fio_nvpf and fiop->fio_vecs[].fv_buflen cannot  contain
		 a frame.

		 In  a ILP32 environment, more data than UINT_MAX would be set
		 in fv_actlen.

       ERANGE
		 During vnd_frameio_write, the size of a frame	is  less  than
		 the  device's	minimum transmission unit or it is larger than
		 the size of the maximum transmission unit.

EXAMPLES
       Example 1    Read a single frame with a single vector

       The following sample C program  opens  an  existing  vnd	 device	 named
       "vnd0"  in  the	current	 zone and performs a blocking read of a single
       frame from it.

	 #include <libvnd.h>
	 #include <stdio.h>

	 int
	 main(void)
	 {
	      vnd_handle_t *vhp;
	      vnd_errno_t vnderr;
	      int syserr, i;
	      frameio_t *fiop;

	      fiop = malloc(sizeof (frameio_t) + sizeof (framevec_t));
	      if (fiop == NULL) {
		   perror("malloc frameio_t");
		   return (1);
	      }
	      fiop->fio_version = FRAMEIO_CURRENT_VERSION;
	      fiop->fio_nvpf = 1;
	      fiop->fio_nvecs = 1;
	      fiop->fio_vecs[0].fv_buf = malloc(1518);
	      fiop->fio_vecs[0].fv_buflen = 1518;
	      if (fiop->fio_vecs[0].fv_buf == NULL) {
		   perror("malloc framevec_t.fv_buf");
		   free(fiop);
		   return (1);
	      }

	      vhp = vnd_open(NULL, "vnd1", &vnderr, &syserr);
	      if (vhp != NULL) {
		   if (vnderr == VND_E_SYS)
			(void) fprintf(stderr, "failed to open device: %s",
			    vnd_strsyserror(syserr));
		   else
			(void) fprintf(stderr, "failed to open device: %s",
			    vnd_strerror(vnderr));
		   free(fiop->fio_vecs[0].fv_buf);
		   free(fiop);
		   return (1);
	      }

	      if (frameio_read(vhp, fiop) != 0) {
		   vnd_errno_t vnderr = vnd_errno(vhp);
		   int syserr = vnd_syserrno(vhp);

		   /* Most consumers should retry on EINTR */
		   if (vnderr == VND_E_SYS)
			(void) fprintf(stderr, "failed to read: %s",
			    vnd_strsyserror(syserr));
		   else
			(void) fprintf(stderr, "failed to read: %s",
			    vnd_strerror(vnderr));
		   vnd_close(vhp);
		   free(fiop->fio_vecs[0].fv_buf);
		   free(fiop);
		   return (1);
	      }

	      /* Consume the data however it's desired */
	      (void) printf("received %d bytes0, fiop->fio_vecs[0].fv_actlen);
	      for (i = 0; i < fiop->fio_vecs[0].fv_actlen)
		   (void) printf("%x ", fiop->fio_vecs[0].fv_buf[i]);

	      vnd_close(vhp);
	      free(fiop->fio_vecs[0].fv_buf);
	      free(viop);
	      return (0);
	 }

       Example 2    Write a single frame with a single vector

       The following sample C program  opens  an  existing  vnd	 device	 named
       "vnd0"  in  the	current zone and performs a blocking write of a single
       frame to it.

	 #include <libvnd.h>
	 #include <stdio.h>
	 #include <string.h>

	 int
	 main(void)
	 {
	      vnd_handle_t *vhp;
	      vnd_errno_t vnderr;
	      int syserr;
	      frameio_t *fiop;

	      fiop = malloc(sizeof (frameio_t) + sizeof (framevec_t));
	      if (fiop == NULL) {
		   perror("malloc frameio_t");
		   return (1);
	      }
	      fiop->fio_version = FRAMEIO_CURRENT_VERSION;
	      fiop->fio_nvpf = 1;
	      fiop->fio_nvecs = 1;
	      fiop->fio_vecs[0].fv_buf = malloc(1518);
	      if (fiop->fio_vecs[0].fv_buf == NULL) {
		   perror("malloc framevec_t.fv_buf");
		   free(fiop);
		   return (1);
	      }

	      /*
	       * Fill in your data however you desire. This is an entirely
	       * invalid frame and while the frameio write may succeed, the
	       * networking stack will almost certainly drop it.
	       */
	      (void) memset(fiop->fio_vecs[0].fv_buf, 'r', 1518);
	      fiop->fio_vecs[0].fv_buflen = 1518;

	      vhp = vnd_open(NULL, "vnd0", &vnderr, &syserr);
	      if (vhp != NULL) {
		   if (vnderr == VND_E_SYS)
			(void) fprintf(stderr, "failed to open device: %s",
			    vnd_strsyserror(syserr));
		   else
			(void) fprintf(stderr, "failed to open device: %s",
			    vnd_strerror(vnderr));
		   free(fiop->fio_vecs[0].fv_buf);
		   free(fiop);
		   return (1);
	      }

	      if (frameio_write(vhp, fiop) != 0) {
		   /* Most consumers should retry on EINTR */
		   if (vnderr == VND_E_SYS)
			(void) fprintf(stderr, "failed to write: %s",
			    vnd_strsyserror(syserr));
		   else
			(void) fprintf(stderr, "failed to write: %s",
			    vnd_strerror(vnderr));
		   vnd_close(vhp);
		   free(fiop->fio_vecs[0].fv_buf);
		   free(fiop);
		   return (1);
	      }

	      (void) printf("wrote %d bytes0, fiop->fio_vecs[0].fv_actlen);

	      vnd_close(vhp);
	      free(fiop->fio_vecs[0].fv_buf);
	      free(viop);
	      return (0);
	 }

       Example 3    Read frames comprised of multiple vectors

       The following sample C program is similar to example 1, except  instead
       of reading a single frame consisting of a single vector it reads multi‐
       ple frames consisting of two vectors. The first vector has room for  an
       18 byte VLAN enabled Ethernet header and the second vector has room for
       a 1500 byte payload.

	 #include <libvnd.h>
	 #include <stdio.h>

	 int
	 main(void)
	 {
	      vnd_handle_t *vhp;
	      vnd_errno_t vnderr;
	      int syserr, i, nframes;
	      frameio_t *fiop;

	      /* Allocate enough framevec_t's for 5 frames */
	      fiop = malloc(sizeof (frameio_t) + sizeof (framevec_t) * 10);
	      if (fiop == NULL) {
		   perror("malloc frameio_t");
		   return (1);
	      }
	      fiop->fio_version = FRAMEIO_CURRENT_VERSION;
	      fiop->fio_nvpf = 2;
	      fiop->fio_nvecs = 10;
	      for (i = 0; i < 10; i += 2) {
		   fiop->fio_vecs[i].fv_buf = malloc(18);
		   fiop->fio_vecs[i].fv_buflen = 18;
		   if (fiop->fio_vecs[i].fv_buf == NULL) {
			perror("malloc framevec_t.fv_buf");
			/* Perform appropriate memory cleanup */
			return (1);
		   }
		   fiop->fio_vecs[i+1].fv_buf = malloc(1500);
		   fiop->fio_vecs[i+1].fv_buflen = 1500;
		   if (fiop->fio_vecs[i+1].fv_buf == NULL) {
			perror("malloc framevec_t.fv_buf");
			/* Perform appropriate memory cleanup */
			return (1);
		   }
	      }

	      vhp = vnd_open(NULL, "vnd1", &vnderr, &syserr);
	      if (vhp != NULL) {
		   if (vnderr == VND_E_SYS)
			(void) fprintf(stderr, "failed to open device: %s",
			    vnd_strsyserror(syserr));
		   else
			(void) fprintf(stderr, "failed to open device: %s",
			    vnd_strerror(vnderr));
		   /* Perform appropriate memory cleanup */
		   return (1);
	      }

	      if (frameio_read(vhp, fiop) != 0) {
		   /* Most consumers should retry on EINTR */
		   if (vnderr == VND_E_SYS)
			(void) fprintf(stderr, "failed to read: %s",
			    vnd_strsyserror(syserr));
		   else
			(void) fprintf(stderr, "failed to read: %s",
			    vnd_strerror(vnderr));
		   vnd_close(vhp);
		   /* Perform appropriate memory cleanup */
		   return (1);
	      }

	      /* Consume the data however it's desired */
	      nframes = fiop->fio_nvecs / fiop->fio_nvpf;
	      (void) printf("consumed %d frames!0, nframes);
	      for (i = 0; i < nframes; i++) {
		   (void) printf("received %d bytes of Ethernet Header0,
		       fiop->fio_vecs[i].fv_actlen);
		   (void) printf("received %d bytes of payload0,
		       fiop->fio_vecs[i+1].fv_actlen);
	      }

	      vnd_close(vhp);
	      /* Do proper memory cleanup */
	      return (0);
	 }

       Example 4    Perform non-blocking reads of multiple frames with a
       single vector

       In this sample C program, opens an existing vnd device named "vnd0" in
       the current zone, ensures that it is in non-blocking mode, and uses
       event ports to do device reads.

	 #include <libvnd.h>
	 #include <stdio.h>
	 #include <port.h>
	 #include <unistd.h>
	 #include <errno.h>
	 #include <sys/tpyes.h>
	 #include <fcntl.h>

	 int
	 main(void)
	 {
	      vnd_handle_t *vhp;
	      vnd_errno_t vnderr;
	      int syserr, i, nframes, port, vfd;
	      frameio_t *fiop;

	      port = port_create();
	      if (port < 0) {
		   perror("port_create");
		   return (1);
	      }
	      /* Allocate enough framevec_t's for 10 frames */
	      fiop = malloc(sizeof (frameio_t) + sizeof (framevec_t) * 10);
	      if (fiop == NULL) {
		   perror("malloc frameio_t");
		   (void) close(port);
		   return (1);
	      }
	      fiop->fio_version = FRAMEIO_CURRENT_VERSION;
	      fiop->fio_nvpf = 1;
	      fiop->fio_nvecs = 10;
	      for (i = 0; i < 10; i++) {
		   fiop->fio_vecs[i].fv_buf = malloc(1518);
		   fiop->fio_vecs[i].fv_buflen = 1518;
		   if (fiop->fio_vecs[i].fv_buf == NULL) {
			perror("malloc framevec_t.fv_buf");
			/* Perform appropriate memory cleanup */
			(void) close(port);
			return (1);
		   }
	      }

	      vhp = vnd_open(NULL, "vnd1", &vnderr, &syserr);
	      if (vhp != NULL) {
		   if (vnderr == VND_E_SYS)
			(void) fprintf(stderr, "failed to open device: %s",
			    vnd_strsyserror(syserr));
		   else
			(void) fprintf(stderr, "failed to open device: %s",
			    vnd_strerror(vnderr));
		   /* Perform appropriate memory cleanup */
		   (void) close(port);
		   return (1);
	      }
	      vfd = vnd_pollfd(vhp);
	      if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0) {
		   (void) fprintf(stderr, "failed to enable non-blocking mode: %s",
		       strerrror(errno));
	      }

	      for (;;) {
		   port_event_t pe;

		   if (port_associate(port, PORT_SOURCE_FD, vfd, POLLIN,
		       vhp) != 0) {
			perror("port_associate");
			vnd_close(vhp);
			/* Perform appropriate memory cleanup */
			(void) close(port);
			return (1);
		   }

		   if (port_get(port, &pe, NULL) != 0) {
			if (errno == EINTR)
			     continue;
			perror("port_associate");
			vnd_close(vhp);
			/* Perform appropriate memory cleanup */
			(void) close(port);
			return (1);
		   }

		   /*
		    * Most real applications will need to compare the file
		    * descriptor and switch on it. In this case, assume
		    * that the fd in question that is readable is 'vfd'.
		    */
		   if (frameio_read(pe.portev_user, fiop) != 0) {
			vnd_errno_t vnderr = vnd_errno(vhp);
			int syserr = vnd_syserrno(vhp);

			if (vnderr == VND_E_SYS && (syserr == EINTR ||
			    syserr == EAGAIN))
			     continue;
			(void) fprintf(stderr, "failed to get read: %s",
			    vnd_strsyserror(vnderr));
			vnd_close(vhp);
			/* Perform appropriate memory cleanup */
			(void) close(port);
			return (1);
		   }

		   /* Consume the data however it's desired */
		   nframes = fiop->fio_nvecs / fiop->fio_nvpf;
		   for (i = 0; i < nframes; i++) {
			(void) printf("frame %d is %d bytes large0, i,
			    fiop->fio_vecs[i].fv_actlen);
		   }

	      }

	      vnd_close(vhp);
	      /* Do proper memory cleanup */
	      return (0);
	 }

ATTRIBUTES
       See attributes(5) for descriptions of the following attributes:

       ┌───────────────┬─────────────────────────────────┐
       │ATTRIBUTE TYPE │	 ATTRIBUTE VALUE	 │
       ├───────────────┼─────────────────────────────────┤
       │Stability      │ Committed			 │
       ├───────────────┼─────────────────────────────────┤
       │MT-Level       │ See "THREADING" in libvnd(3LIB) │
       └───────────────┴─────────────────────────────────┘

SEE ALSO
       Intro(2),  getmsg(2),  read(2),	readv(2),  write(2),  writev(2),  lib‐
       vnd(3VND),   vnd_errno(3VND),   vnd_pollfd(3VND),   vnd_syserrno(3VND),
       iovec(9S)

				 Mar 06, 2014		VND_FRAMEIO_READ(3VND)
[top]

List of man pages available for SmartOS

Copyright (c) for man pages and the logo by the respective OS vendor.

For those who want to learn more, the polarhome community provides shell access and support.

[legal] [privacy] [GNU] [policy] [cookies] [netiquette] [sponsors] [FAQ]
Tweet
Polarhome, production since 1999.
Member of Polarhome portal.
Based on Fawad Halim's script.
....................................................................
Vote for polarhome
Free Shell Accounts :: the biggest list on the net