EtherNet/IP
Synopsis
Director reads one controller that speaks EtherNet/IP: the tags of a Rockwell Automation ControlLogix or CompactLogix, of a Micro800, or of another controller that reads its tags by their names over CIP. Nothing is installed on the controller or beside it: Director connects as an HMI or a data collector would, over TCP (port 44818), sends read requests, and writes what comes back as ECS records. It never writes to the controller: the only services it sends read a tag, read who the controller is, or open and close the connection the reads go over.
One device, one controller. Monitoring twelve controllers takes twelve devices. The device holds one session with its controller, and one connection to its CPU, and sends its requests over them one at a time. A controller has few connections to spare.
What to read is declared by datasets. A controller's tags have names, and a client reads them by name, so the device's datasets are your own, each a table of tags read on the dataset's own interval. For example, the line's count, the DINT Line1_Count; a tank's level, the REAL Tank3.Level; or a program's speed, Program:MainProgram.Speed. Each tag is declared with the type it is read as, and a tag of another type is left out rather than read as what it is not.
The device dials the controller and binds no port, so any number of EtherNet/IP devices, on one Director or several, can name port 44818, and none of them blocks a listener. The device runs on Director only; no agent runs it.
It is the counterpart, for Rockwell controllers, of the Siemens S7 device.
The EtherNet/IP device needs Director 2.4.1 or later. With no Director or cluster at that version selected, the wizard shows EtherNet/IP devices are unavailable on directors or clusters below version 2.4.1 and the device cannot be created.
Schema
- id: <numeric>
name: <string>
description: <string>
type: ethernet_ip
tags: <string[]>
pipelines: <pipeline[]>
status: <boolean>
properties:
address: <string>
port: <numeric>
route: <string>
connected_messaging: <boolean>
connection_size: <numeric>
timeout: <numeric>
max_tags_per_request: <numeric>
definitions: <definition[]>
Configuration
The following fields are used to define the device:
Device
| Field | Required | Default | Description |
|---|---|---|---|
id | Y | - | Unique numeric identifier |
name | Y | - | Device name |
description | N | - | Optional description |
type | Y | - | Must be ethernet_ip |
tags | N | - | Optional tags |
pipelines | N | - | Optional pre-processor pipelines |
status | N | true | Enable/disable the device |
Connection
| Field | Required | Default | Description |
|---|---|---|---|
address | Y | - | Host name or IP address of the controller's Ethernet module. An IPv6 address can be written as it is or in brackets. A wildcard address (0.0.0.0, ::) is refused, and so is a port written into the address: the port is its own field. |
port | N | 44818 | EtherNet/IP's port for explicit messages, from 1 to 65535 |
route | N | 1,0 | The way from the Ethernet module to the CPU, as a Logix path writes it: pairs of a port and a link address, or direct (also none) for no route. Left out or empty is 1,0. See Routes. |
connected_messaging | N | true | Reads over a CIP connection to the CPU, falling back to unconnected messages when the controller refuses one. false reads with unconnected messages from the start. See Connected and Unconnected Messaging. |
connection_size | N | 4002 | The size of the connection the device asks for, in bytes, from 500 to 4002. A controller that refuses a Large Forward Open is asked for 504. Not used with connected_messaging: false, and the device's log says so. |
timeout | N | 10 | Seconds a connect and each request wait for their answer, from 1 to 300 |
max_tags_per_request | N | 200 | How many tags one request reads at most, from 1 to 200, for a controller that takes fewer. The size of a message may make it fewer still. See Requests. |
A device that fails these checks does not start, and its state is Configuration error with the reason. Examples are a missing or wildcard address, a route that is not pairs of a port and a link address, or a connection size or a timeout out of range. The device stops before it dials anything.
Connection
Routes
Director dials the controller's Ethernet module and registers an EtherNet/IP session. The module that answers is not always the CPU: in a ControlLogix chassis the Ethernet module is one card and the CPU another. So a request names the route from the one to the other, as a Logix path does: pairs of a port of the module the request leaves by and the link address it goes to on that port.
route | What it reaches |
|---|---|
1,0 | Port 1, the backplane, and the CPU in slot 0: a CompactLogix's CPU, and most often a ControlLogix's. The default. |
1,3 | The CPU in slot 3 of the chassis |
direct | No route: the Ethernet port is the controller's own. A Micro800. |
1,3,2,10.20.0.5,1,0 | Through the Ethernet module in slot 3, out of its port 2 to the module at 10.20.0.5, and to the CPU in slot 0 of that chassis |
A port is a number from 1 to 65535. A link address is a number from 0 to 255 (a slot, a node) or, for a port on an Ethernet network, an IP address or a host name. A route has at most 8 hops and takes at most 64 bytes of a request.
The route is the setting most often wrong. A ControlLogix CPU is a card of its own, so its route names its slot (1,<slot>); a CompactLogix's is 1,0; a Micro800 takes direct.
Who the Controller Is
Once the session stands, the device reads the controller's Identity object, the way its tags are read. The answer names the controller in the device's log, for example the controller is a 1756-L83E/B, revision 32.11, and proves the route: a route that leads nowhere is found here, before any tag is read, and is a Connection error that says to check the route.
Connected and Unconnected Messaging
- Connected (the default). The device opens a class 3 connection to the CPU along the route and reads over it. It first asks for a Large Forward Open of
connection_sizebytes (4002, the largest a Logix controller takes), and for a Forward Open of 504 bytes when the controller refuses that, as a Micro800 and older firmware do. Aconnection_sizeof511or less is asked for with a Forward Open at once. The connection is closed, and the session ended, when the device stops, so the controller is not left a connection to time out. - Unconnected. A controller that refuses a connection altogether, because it has none to spare or none at all, is read with unconnected messages instead, each carried along the route by the controller's Connection Manager. The device's log says so, with the controller's reason.
connected_messaging: falsereads this way from the start.
A controller's connections are a budget. A connected device takes one of the controller's CIP connections for as long as it runs. With connected_messaging: false it takes none, at the cost of smaller messages (504 bytes) and so more requests for a large table.
Idle and Lost Connections
- Idle connections. A controller gives up a connection it has not heard on for about two minutes, and answers a request on it with nothing. So the device reopens a connection it has not used for 96 seconds before it sends. A dataset read every five minutes costs two extra short requests a reading, and never a timeout; datasets read every minute or faster keep their connection.
- Lost sessions. A session the controller closed between two readings is opened again and the reading tried once more, so a reading is not lost to the controller having hung up. A controller that cannot be connected to is tried again at every reading, without limit. The failure is logged once for as long as it lasts, and again when it is over.
External Access
A Logix controller answers only for tags whose External Access is Read/Write or Read Only. A tag set to None is refused with "access is denied" (status 0x0F), and the device's log says what to change.
Datasets
The device's definitions are its datasets. In a configuration file each dataset is a definition named ethernet_ip_tag_collector, the device's one dataset type:
| Dataset | Definition | Definition ID | Kind | One record per |
|---|---|---|---|---|
tag | ethernet_ip_tag_collector | 32150 | metric | reading of the dataset's table |
- Any number of datasets. Each dataset is a table of its own, read on its own interval, so a device reads as many as are assigned: for example, the line's values every 10 seconds and its alarm bits every 5.
- Pipelines. A dataset's records enter the pre-processing pipeline the dataset selects, or the device's when it selects none.
- Nothing assigned is allowed. The device then only checks, every minute, that its controller takes a session, and a connection when it reads over one, so its connection state stays current, and writes nothing.
- A dataset that cannot be read is left out, with a warning in the device's log that names it and says why: no table, a tag or a type that is missing, or a field named twice. The rest of the device runs. With every dataset assigned to it left out, the device stops with Configuration error.
Dataset Properties
| Field | Required | Default | Description |
|---|---|---|---|
table | Y | - | The name the dataset's fields sit under in a record (see Records): letters, digits, and underscores, at most 64, not starting with a digit. table is reserved. |
interval | N | 60 | Seconds between readings, 1 or more. A duration such as 5m is also read. |
labels | N | - | An object of names and values written on every record as ECS labels. At most 32; a name is letters, digits, underscores, and hyphens, and a value is text, a number, or a switch of at most 256 characters. |
pipeline_name | N | the device's | The pre-processing pipeline the dataset's records enter |
Fields
A dataset's inputs are its fields, at most 512. Each needs a name, unique in the table: letters, digits, and underscores, at most 64, not starting with a digit. An input with status: false is left out, and not validated.
| Field | Required | Description |
|---|---|---|
tag | Y | The tag, as the controller's program names it. See Tags. |
type | Y | The type the tag is read as, which has to be the one the controller holds it as. See Types. |
Tags
| Written | Reads |
|---|---|
Line1_Count | A tag of the controller's scope |
Program:MainProgram.Speed | A tag of a program |
Tank3.Level | A member of a structure |
Counts[4], Grid[1,2] | An element of an array, of up to three dimensions |
Zones[2].Setpoint | A member of an element |
Status.3 | One bit of a whole number, the lowest bit 0, up to 63. Its type is bool. |
A name is letters, digits, and underscores, not starting with a digit, at most 128 characters; a tag is at most 255 characters. Names are sent as they are written, and a controller reads them in any case.
A field reads one value. An array is read an element a field, and a structure a member a field: a tag that is a whole structure is refused with name the member to read. A Logix STRING is the exception: it is read as text.
Types
| Type | The controller's type | Written as |
|---|---|---|
bool | BOOL | true or false |
sint, int, dint, lint | SINT, INT, DINT, LINT | A whole number, signed |
usint, uint, udint, ulint | USINT, UINT, UDINT, ULINT | A whole number |
byte, word, dword, lword | BYTE, WORD, DWORD, LWORD | A whole number, the bit string's bits |
real, lreal | REAL, LREAL | A number. A REAL is written as the shortest decimal that reads back as it. |
string | STRING | Text: a Logix STRING, a string type of the program's own, or a Micro800's |
The type has to be the one the controller holds the tag as. Every answer names the tag's type, and the device holds it against the field's: a field declared dint whose tag is a REAL is left out of the record, and the device's log names both types, rather than reading it as a wrong number.
Three things are read out of another type, by design:
- One bit of a tag (
Status.3, typebool) is read out of the whole number the controller answers, of any of the whole-number and bit-string types. - An element of a
BOOLarray (Alarms[37], typebool) is read out of the 32-bit word a Logix controller keeps it in. No setting is needed. A controller that keeps eachBOOLon its own is found out, and the element read by its own index from the next reading on. - A string is a structure in a Logix controller, a length and its characters, which the device reads as text, so a string type of the program's own is read as a
STRINGis. Characters are read as ISO 8859-1, a byte each.
A float that is not a number (a NaN or an infinity) holds no value: the field is left out, and the device's log says so.
Requests
A field is one read of one tag, so a tag the controller refuses is the only one left out. The reads of a dataset are packed into Multiple Service Packets in the order the fields are declared, each holding as many as fit:
- at most
max_tags_per_request; - within the size of a message, for the request and for its answer. Over a connection a message is the connection's size less two bytes (
4000, or502); without one it is 504 bytes. Over a large connection, a table of two hundredDINTs is one request.
What the controller says of a request changes how the next ones are cut, in the same reading:
- A controller that takes no Multiple Service Packet, as a Micro800 does by Rockwell's manuals, says so the first time it is asked for several tags. Its tags are read one a request from then on. No setting is needed, but expect a table of two hundred tags to be two hundred requests a reading there.
- A request whose answer does not fit a message is read a tag a request from then on.
- A tag whose value does not fit a message, such as a long string of the program's own, is read whole in as many requests as it takes, up to 64 KiB.
The requests are planned for the limits of the current session, and planned again when a new session has others.
Readings
- At start the device reads every dataset once.
- Each dataset on its own interval after that, from the start of one reading to the start of the next.
- Datasets due at the same time are read one after the other over the one session. A reading that takes longer than its interval delays the next, which starts a moment after it ends.
Records
Every record is one ECS 8.11 document with the following fields:
| Field | Value |
|---|---|
@timestamp | The reading's time |
ecs.version | 8.11.0 |
event.module | ethernet_ip |
event.dataset | ethernet_ip.tag |
event.kind | metric |
event.category, event.type | host, info |
observer.name | The device's name in the console |
observer.hostname | The Director's host name |
observer.vendor, observer.product | VirtualMetric, EtherNet/IP |
server.address, server.port | The address the device is configured with, and its port |
server.ip | The address, when it is an IP address |
network.protocol, network.transport | enip, tcp |
labels.<name> | The dataset's labels, when it has any |
ethernet_ip.tag.table | The dataset's table |
ethernet_ip.tag.<table>.<field> | The value of each field that was read, as Types writes it |
The values sit under the table's name, so two tables can name a field alike with different types without one mapping conflicting with the other.
{
"@timestamp": "2026-10-14T12:00:00Z",
"ecs": { "version": "8.11.0" },
"event": {
"module": "ethernet_ip",
"dataset": "ethernet_ip.tag",
"kind": "metric",
"category": ["host"],
"type": ["info"]
},
"observer": {
"vendor": "VirtualMetric",
"product": "EtherNet/IP",
"name": "packaging-line-plc",
"hostname": "director01"
},
"server": { "address": "192.0.2.50", "ip": "192.0.2.50", "port": 44818 },
"network": { "protocol": "enip", "transport": "tcp" },
"labels": { "machine": "packer-1" },
"ethernet_ip": {
"tag": {
"table": "line",
"line": {
"speed": 12.5,
"packs": 48211,
"running": true,
"recipe": "cola"
}
}
}
}
A field with no value is absent from that record: a tag the controller refused, one of another type than the field declares, or one whose bytes hold no value of its type. The device's log says so once, with the reason, for as long as it lasts. A record with no field is not written.
Device State
The connection state follows the controller, and the first of these that holds is the state:
- Connected while the controller answers any tag of the device's datasets with a value. A device with no dataset assigned is Connected while its controller takes a session, and a connection when the device reads over one.
- Configuration error while the controller answers the device's requests, but with no value for any tag of any dataset: tags it does not have, types it does not hold them as, External Access set to None, or a route that ends at the wrong module. The message names the refusal and what to change. A configuration that cannot run is a Configuration error too (see Configuration).
- Connection error while the controller cannot be connected to, its route leads nowhere, or it answered none of the requests of any dataset at its latest reading.
The state follows every dataset's latest reading, not only the datasets of the reading in progress. A record that could not be written, or a failure inside one dataset, affects that dataset alone and does not change the device's state.
What the controller answers a tag with, and what to do about it:
| Status | Said | To do |
|---|---|---|
0x04, 0x05 | It does not understand the path, or the path names nothing | Check the tag's spelling, its scope (Program:<program>.<tag>), and its index. |
0x0F | Access is denied | The tag's External Access is None, or the controller's security does not let it be read. |
0x08 | It does not have the service | The route has to end at the CPU of a Logix or a Micro800 controller. |
0xFF, extended 0x2105 | The element is past the end of the tag | The index is past the end of the array. |
0x01, extended 0x0204, 0x0311, 0x0312, 0x0315, 0x0318 | The request could not be carried along the route | Check the route: 1 and the CPU's slot, or direct. |
The EtherNet/IP device is not simulated. A dataset's records are the values of your own tags, a shape a generated sample cannot stand in for.
Not Supported
- Implicit (class 1) I/O, and anything over UDP, such as port
2222. - PCCC controllers: PLC-5, SLC 500, and MicroLogix, which have no tags to read by name.
- Reading a whole structure or a whole array as one field; reading a tag list or a structure's template from the controller; times and dates as their own types.
- CIP Security (TLS on port
2221). - Writing: no tag is written, and no service that changes the controller is sent.
Compatibility
The device follows The CIP Networks Library and Rockwell's Logix 5000 Data Access manual. When a controller does not accept a request the device prefers, such as a Multiple Service Packet or a Large Forward Open on a Micro800, the device falls back to a simpler request. A controller that answers in a way the device does not expect is read more slowly, or the device reports why it cannot read a tag. It does not return a wrong value.
Console
In the console, go to
General settings , as on every device.Connection settings :Address ,Port ,Route to the CPU , andConnected messaging .Route to the CPU is a choice, and writesrouteas the table below shows.Connected messaging is a toggle, enabled by default.Connection size shows only while it is enabled, andconnection_sizeis not written while it is disabled.
Advanced settings :Timeout andMaximum tags per request .Data collection : the EtherNet/IP datasets the device reads.Review and create .
| Shows | Writes | |
|---|---|---|
0 by default | route: "1,<slot>" | |
| Nothing | route: direct | |
The route as typed, such as 1,3,2,192.0.2.60,1,0 |
The device's page has the same tabs, and 1,3 opens on 3, and one that names no route opens on 0; one stored with direct or none opens on
An EtherNet/IP dataset is created in type: dint); see Types.
The console refuses two addresses the Director would take: a host name whose labels are not letters, digits, and hyphens, and an IPv6 address with a zone. Its checks of routes and tags are otherwise the Director's.
Examples
ControlLogix
Reading the packaging line's values every 10 seconds and its alarm bits every 5, from a ControlLogix whose CPU is in slot 2... | |
Micro800
Reading a Micro850, whose Ethernet port is the controller's own, so it is reached with no route. It reads one tag a request, which the device finds out... | |
Second Chassis, Unconnected
Reading a CPU in a second chassis, through the Ethernet module in slot 3 of the chassis Director connects to, with unconnected messages alone, so it takes none of that controller's connections... | |