ZMQAPI Protocol

The ZMQAPI protocol is used by yangcli-gw to communicate with client application programs.

Warning

The ZMQAPI Protocol definition is still preliminary and may change in the future.

ZMQAPI Roles

There are three operational roles supported in the protocol. Actual implementations may combine or somehow split these roles.

ZMQAPI Server Role

The yangcli-gw program is a ZMQAPI server. A ZMQAPI server has the following tasks:

  • It listens for commands from client applications.

  • It initiates and maintains network management sessions with managed devices on behalf of client applications

  • It sends notification messages to client applications

ZMQAPI Client Role

Your application program is a ZMQAPI client. A ZMQAPI client has the following tasks:

  • It connects to yangcli-gw as needed

  • It sends command requests to yangcli-gw

  • It listens for command responses from yangcli-gw

ZMQAPI Collector Role

Your application program is a ZMQAPI collector. It can be co-located with the ZMQAPI client role. Notification delivery usually needs to be configured first using the client role.

A ZMQAPI collector has the following tasks:

  • It listens for notifications from yangcli-gw

ZMQAPI Message Types

All ZMQAPI messages are ZeroMQ Multipart Messages. There are three message types defined:

Client Request Message (REQ):

  • Used to access the asynchronous command channel

  • Sent from the application to yangcli-gw

  • Requests may be serialized by yangcli-gw

  • Message definition: ZMQAPI REQ Message

Server Response Message (REP):

  • Sent by yangcli-gw to a client application after a client request message has been received

  • ZMQAPI header contains a simple command status field

  • Message definition: ZMQAPI REP Message

  • Payload section will depend on the return status

    • ok: The payload will be text

    • error: The payload format and contents will depend on the error information available to yangcli-gw

    • data: The payload format requested by the client application will be used for the returned data

Server Notification Message (PUB):

  • Sent by yangcli-gw when some event occurs that requires that the client application be notified of the event.

  • Must be setup using the <establish-subscription> operation or other mechanisms in order to receive NETCONF notifications.

  • There are three types of server notifications:

    • gw: Control messages from yangcli-gw

    • stream: Event stream subscription notification from a NETCONF server

    • data: YANG Push Datastore subscription notification from a NETCONF server

ZMQAPI Message Encoding

ZMQAPI uses a flexible message encoding scheme:

ZMQAPI Message Header

All ZMQAPI messages begin with a ZMQAPI Header.

  • Text format

  • Contains one line

  • Text fields are separated by one space ' ' character

  • Separator character between fields must be one space character.

  • Max Header Size: 4095 bytes

    • ZeroMQ message parts do not contain trailing zero bytes

    • The receive buffer must be 4096 bytes including one byte for a terminating zero byte.

../_images/zmqapi_header.png

ZMQAPI Header Fields

Header Field

Description

Protocol ID

Text string representing the protocol version.

Message ID

Text code representing the ZMQAPI message type.

Response Format

Text code representing the payload format. Usage depends on the Message ID

Message Specific

Usage depends on the Message ID

Example Header

ZMQAPI.1 REQ R2 client1 edb5debc-1dc7-11ee-be86-e9f635d13331
  • Protocol ID: ZMQAPI.1

  • Message ID: REQ

  • Response Format: R2

  • Message Specific: client1 edb5debc-1dc7-11ee-be86-e9f635d13331

ZMQAPI Protocol ID

This is always the first field in the ZMQAPI message header. It contains the string ZMQAPI, followed by a period character (.), followed by the protocol version number.

  • The current protocol version is '1'

  • The string ZMQAPI.1 must be used for this protocol version

  • This field must be followed by one space ' ' character

ZMQAPI Message ID

This is always the second field in the ZMQAPI message header. It contains a 3 character string representing the ZMQAPI message type. The following values are defined in ZMQAPI.1:

This field must be followed by one space ' ' character.

ZMQAPI Response Format

This is always the third field in the ZMQAPI message header. It contains a 2 character string representing the ZMQAPI payload encoding format.

  • In a REQ header this is the requested format for the response payload in the REP message from the server

  • In a REP or PUB header this is the actual format of the payload in the message.

The response format consists of the letter 'R', followed by the numeric ID for the encoding format

The following values are defined in ZMQAPI.1:

  • R0: No payload. In this mode only headers will be sent and no payload portions will follow.

    • This value will not be used in a PUB message.

    • It can be used in a REQ message by a client to suppress the actual payload response.

    • It will be used in a REP message by yangcli-gw if no payload is included in the response.

  • R1: Plain text payload. The default yangcli-pro display format will be used in the payload section.

  • R2: Plain JSON payload. The payload will be encoded in JSON without any module prefixes.

  • R3: IETF JSON payload. The payload will be encoded in JSON with module prefixes, as defined in RFC 7951.

  • R4: XML payload. The payload will be encoded in XML 1.0 format.

This field must be followed by one space ' ' character, only if there are any more fields in the ZMQAPI header for the specific message.

ZMQAPI Response Format Examples

This example shows the same data retrieval response payload in each of the four formats.

The request used in this example:

> sget /interfaces-state

Example: R1 Response Format (Plain)

rpc-reply {
  {
    interfaces-state {
      interface  lo {
        name lo
        type ianaift:softwareLoopback
        admin-status up
        oper-status up
        if-index 1
        phys-address 00:00:00:00:00:00
        speed 0
        statistics {
          in-octets 12617816
          in-unicast-pkts 109261
          in-multicast-pkts 0
          in-discards 0
          in-errors 0
          out-octets 12617816
          out-unicast-pkts 109261
          out-discards 0
          out-errors 0
        }
      }
      interface  eno1 {
        name eno1
        type ianaift:ethernetCsmacd
        admin-status up
        oper-status up
        if-index 2
        phys-address 3c:7c:3f:1d:83:aa
        speed 1000000000
        statistics {
          in-octets 8435787307
          in-unicast-pkts 9992246
          in-multicast-pkts 808894
          in-discards 177033
          in-errors 0
          out-octets 19278785748
          out-unicast-pkts 14440784
          out-discards 0
          out-errors 0
        }
      }
      interface  virbr0 {
        name virbr0
        type ianaift:ethernetCsmacd
        admin-status up
        oper-status down
        if-index 3
        phys-address 52:54:00:7e:68:35
        speed 0
        statistics {
          in-octets 0
          in-unicast-pkts 0
          in-multicast-pkts 0
          in-discards 0
          in-errors 0
          out-octets 0
          out-unicast-pkts 0
          out-discards 0
          out-errors 0
        }
      }
    }
  }
}

Example: R2 Response Format (JSON)

{
  "rpc-reply": {
    "data": {
      "interfaces-state": {
        "interface": [
          {
            "name":"lo",
            "type":"iana-if-type:softwareLoopback",
            "admin-status":"up",
            "oper-status":"up",
            "if-index":1,
            "phys-address":"00:00:00:00:00:00",
            "speed":"0",
            "statistics": {
              "in-octets":"12627651",
              "in-unicast-pkts":"109334",
              "in-multicast-pkts":"0",
              "in-discards":0,
              "in-errors":0,
              "out-octets":"12627651",
              "out-unicast-pkts":"109334",
              "out-discards":0,
              "out-errors":0
            }
          },
          {
            "name":"eno1",
            "type":"iana-if-type:ethernetCsmacd",
            "admin-status":"up",
            "oper-status":"up",
            "if-index":2,
            "phys-address":"3c:7c:3f:1d:83:aa",
            "speed":"1000000000",
            "statistics": {
              "in-octets":"8444440799",
              "in-unicast-pkts":"10001057",
              "in-multicast-pkts":"809479",
              "in-discards":177125,
              "in-errors":0,
              "out-octets":"19306372099",
              "out-unicast-pkts":"14460132",
              "out-discards":0,
              "out-errors":0
            }
          },
          {
            "name":"virbr0",
            "type":"iana-if-type:ethernetCsmacd",
            "admin-status":"up",
            "oper-status":"down",
            "if-index":3,
            "phys-address":"52:54:00:7e:68:35",
            "speed":"0",
            "statistics": {
              "in-octets":"0",
              "in-unicast-pkts":"0",
              "in-multicast-pkts":"0",
              "in-discards":0,
              "in-errors":0,
              "out-octets":"0",
              "out-unicast-pkts":"0",
              "out-discards":0,
              "out-errors":0
            }
          }
        ]
      }
    }
  }
}

Example: R3 Response Format (IETF-JSON)

{
  "ietf-netconf:rpc-reply": {
    "ietf-netconf:data": {
      "ietf-interfaces:interfaces-state": {
        "interface": [
          {
            "name":"lo",
            "type":"iana-if-type:softwareLoopback",
            "admin-status":"up",
            "oper-status":"up",
            "if-index":1,
            "phys-address":"00:00:00:00:00:00",
            "speed":"0",
            "statistics": {
              "in-octets":"12639445",
              "in-unicast-pkts":"109414",
              "in-multicast-pkts":"0",
              "in-discards":0,
              "in-errors":0,
              "out-octets":"12639445",
              "out-unicast-pkts":"109414",
              "out-discards":0,
              "out-errors":0
            }
          },
          {
            "name":"eno1",
            "type":"iana-if-type:ethernetCsmacd",
            "admin-status":"up",
            "oper-status":"up",
            "if-index":2,
            "phys-address":"3c:7c:3f:1d:83:aa",
            "speed":"1000000000",
            "statistics": {
              "in-octets":"8444701815",
              "in-unicast-pkts":"10002184",
              "in-multicast-pkts":"809818",
              "in-discards":177231,
              "in-errors":0,
              "out-octets":"19306453840",
              "out-unicast-pkts":"14460456",
              "out-discards":0,
              "out-errors":0
            }
          },
          {
            "name":"virbr0",
            "type":"iana-if-type:ethernetCsmacd",
            "admin-status":"up",
            "oper-status":"down",
            "if-index":3,
            "phys-address":"52:54:00:7e:68:35",
            "speed":"0",
            "statistics": {
              "in-octets":"0",
              "in-unicast-pkts":"0",
              "in-multicast-pkts":"0",
              "in-discards":0,
              "in-errors":0,
              "out-octets":"0",
              "out-unicast-pkts":"0",
              "out-discards":0,
              "out-errors":0
            }
          }
        ]
      }
    }
  }
}

Example: R4 Response Format (XML)

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <data>
    <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
      <interface>
        <name>lo</name>
        <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:softwareLoopback</type>
        <admin-status>up</admin-status>
        <oper-status>up</oper-status>
        <if-index>1</if-index>
        <phys-address>00:00:00:00:00:00</phys-address>
        <speed>0</speed>
        <statistics>
          <in-octets>12698433</in-octets>
          <in-unicast-pkts>109946</in-unicast-pkts>
          <in-multicast-pkts>0</in-multicast-pkts>
          <in-discards>0</in-discards>
          <in-errors>0</in-errors>
          <out-octets>12698433</out-octets>
          <out-unicast-pkts>109946</out-unicast-pkts>
          <out-discards>0</out-discards>
          <out-errors>0</out-errors>
        </statistics>
      </interface>
      <interface>
        <name>eno1</name>
        <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>
        <admin-status>up</admin-status>
        <oper-status>up</oper-status>
        <if-index>2</if-index>
        <phys-address>3c:7c:3f:1d:83:aa</phys-address>
        <speed>1000000000</speed>
        <statistics>
          <in-octets>8462476977</in-octets>
          <in-unicast-pkts>10020558</in-unicast-pkts>
          <in-multicast-pkts>811254</in-multicast-pkts>
          <in-discards>177452</in-discards>
          <in-errors>0</in-errors>
          <out-octets>19334939852</out-octets>
          <out-unicast-pkts>14483261</out-unicast-pkts>
          <out-discards>0</out-discards>
          <out-errors>0</out-errors>
        </statistics>
      </interface>
      <interface>
        <name>virbr0</name>
        <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>
        <admin-status>up</admin-status>
        <oper-status>down</oper-status>
        <if-index>3</if-index>
        <phys-address>52:54:00:7e:68:35</phys-address>
        <speed>0</speed>
        <statistics>
          <in-octets>0</in-octets>
          <in-unicast-pkts>0</in-unicast-pkts>
          <in-multicast-pkts>0</in-multicast-pkts>
          <in-discards>0</in-discards>
          <in-errors>0</in-errors>
          <out-octets>0</out-octets>
          <out-unicast-pkts>0</out-unicast-pkts>
          <out-discards>0</out-discards>
          <out-errors>0</out-errors>
        </statistics>
      </interface>
    </interfaces-state>
  </data>
</rpc-reply>

ZMQAPI Message Specific Parts

The format of the remaining parts of the ZMQAPI header depends on the message type.

[fill in with links to the specific message parts]

ZMQAPI SESSION Header

The SESSION header is a simple JSON object containing information about the current session. It is sent by yangcli-gw in server response (REP) and server notification (PUB) messages.

  • JSON format

  • Contains one line

  • Max Header Size: 4095 bytes

    • ZeroMQ message parts do not contain trailing zero bytes

    • The receive buffer must be 4096 bytes including one byte for a terminating zero byte.

../_images/session_header.png

SESSION Header Fields

Header Field

Description

count

Current connected session count.

sid

Session ID or zero if not connected.

name

Session name or default if not connected.

server

Server address or empty string if not connected.

port

Server port or empty string if not connected.

user

User name or empty string if not connected.

SESSION Header YANG

The YANG module yumaworks-zmqapi.yang contains the 'session-hdr' grouping, which defines the contents of this header.

grouping session-hdr {
    description
      "Represents the 'session' header contents sent in
       all ZMQAPI.1 'REP' and 'PUB' messages.";
    leaf count {
      type uint32;
      description
        "Number of sessions currently active in the
         yangcli-gw server.";
    }
    leaf sid {
      type uint32;
      description
        "Session ID of the current session or 0 if
         current session is not connected.";
    }
    leaf name {
      type yang:yang-identifier;
      description
        "Session name of the current session.
         This will be set to the value 'default' unless
         named sessions are used.";
    }
    leaf server {
      type string;
      description
        "Address of the server for the current session.
         If the 'sid' is set to zero then this value
         will be an empty string.";
    }
    leaf port {
      type uint16;
      description
        "TCP port number of the server for the current session.
         If the 'sid' is set to zero then this value will be zero.";
    }
    leaf user {
      type string;
      description
        "User name string used for the current session.
         If the 'sid' is set to zero then this value
         will be an empty string.";
    }
}

SESSION Header Examples

Example SESSION Header If No Session Connected

{"count":0,"sid":0,"name":"default","server":"","port":0,"user":""}

Example SESSION Header If Default Session Connected to Localhost

{"count":1,"sid":1,"name":"default","server":"localhost","port":830,"user":"andy"}

ZMQAPI EVENT Header

The EVENT header is a simple JSON object containing information about the event reported in a ZMQAPI PUB Message.

  • JSON format

  • Contains one line

  • Max Header Size: 4095 bytes

    • ZeroMQ message parts do not contain trailing zero bytes

    • The receive buffer must be 4096 bytes including one byte for a terminating zero byte.

../_images/event_header.png

EVENT Header Fields

Header Field

Description

type

Event Type enumeration

time

event timestamp (e.g. eventTime)

observer

Observer ID (or 0 if none reported)

module

YANG module name containing event definition

revision

YANG module revision containing event definition

name

event identifier

path

YANG path to notification (/ for top-level)

EVENT Header YANG

The YANG module yumaworks-zmqapi.yang contains the 'event-hdr' grouping, which defines the contents of this header.

grouping event-hdr {
    description
      "Represents the 'event' header sent in ZMQAPI.1
       PUB messages.";
    leaf type {
      type enumeration {
        enum gw {
          description
            "The event is from yangcli-gw, not a managed server";
        }
        enum stream {
          description
            "The event is from an event stream subscription.";
        }
        enum data {
          description
            "The event is from a datastore subscription.";
        }
      }
      description
        "The type of event that is contained in the event
         payload section of the PUB message.";
    }
    leaf time {
      type yang:date-and-time;
      description
        "The eventTime reported by the server or the
         current time for a 'gw' event type.";
    }
    leaf observer {
       type uint32;
       description
         "The observer identifier for the event source.
          The value '0' is used for 'gw' and 'stream'
          message types.  It is possible the observer
          identifier will be set for a 'data' event type.";
    }
    leaf module {
        type yang:yang-identifier;
        description
          "The YANG module name containing the event
           definition for the event payload portion
           of the message.

           Note that the module name for the top-level
           element in a YANG 1.1 notification may not
           be the same as the notification.";
    }
    leaf revision {
         type string;
         description
           "The revision date for the 'module' leaf.
            This is an empty string if no revision string
            is available.";
    }
    leaf name {
        type yang:yang-identifier;
        description
           "The event name for this PUB message.";
    }
    leaf path {
        type string;
        description
          "The datastore path to the event.
           The string format is a RESTCONF instance-identifier
           as defined in RFC 7951.

            - For 'gw' type events this will always be the root.
            - For 'stream' and 'data' type events:
              - this will be the root for top-level events.
              - this will be the path to the parent of the nested
                notification for YANG 1.1 nested notifications or
                schema-mounted notifications.
           ";
    }
}

EVENT Header Examples

TBD