Reading Logix Tags Over EtherNet/IP: Connections, RPI, and Batched Reads
Pulling ControlLogix and CompactLogix tags over EtherNet/IP: connected versus unconnected CIP, RPI, connection budgets, and why array reads win.
The symptom that starts most of these calls: SCADA has been reading 300 tags from a ControlLogix rack for a year, someone adds a second HMI and a reporting server, and now all three clients show intermittent bad quality. The PLC scan time never moved. What moved is the number of CIP connections open to the controller, and you have quietly run into a ceiling nobody wrote down.
EtherNet/IP is not a fieldbus in the Modbus sense. It is CIP — the Common Industrial Protocol, defined by ODVA — carried over standard Ethernet. When your SCADA reads a Logix tag, it is not reading a register at an address. It is asking the controller, by name, for the value of a symbolic tag, over a CIP connection that had to be negotiated first. Everything that makes EtherNet/IP fast or slow comes back to how those connections and requests are structured.
Two kinds of messaging, and SCADA only uses one
CIP has implicit and explicit messaging, and the distinction matters because people conflate them.
Implicit (Class 1) messaging is the cyclic I/O data — a drive, a remote I/O rack, a Point I/O adapter exchanging its input and output image with the controller at a fixed rate. It runs over UDP (port 2222), it is connected, and its rate is the RPI, the Requested Packet Interval. This is PLC-to-device traffic. Your SCADA almost never participates in it.
Explicit (Class 3) messaging is request/response: "give me the value of Tank_101_Level." It runs over TCP (port 44818), and it is what a SCADA EtherNet/IP driver actually does. It can be connected (a Forward Open establishes a Class 3 connection the driver reuses) or unconnected (each request stands alone, routed via the Unconnected Message Manager).
The practical rule: for steady polling of the same tag list, you want the driver using connected Class 3 messaging. Unconnected messaging is fine for a one-shot read during commissioning, but as a polling strategy it re-pays the routing overhead on every request and gives you nothing to reuse.
The connection budget is the real limit
Here is the number that ends up mattering more than bandwidth or scan time: a Logix communications module has a finite pool of CIP connections. A 1756-EN2T, the common ControlLogix Ethernet module, supports 256 CIP connections and 128 TCP/IP connections. Those are consumed by everything — produced/consumed tags between controllers, drives, remote I/O, and every HMI and SCADA client holding a Class 3 connection open.
Add clients without accounting for this and you don't get a graceful slowdown. You get Forward Open rejections. New connections fail while existing ones keep working, which is exactly why the problem looks like "the third client is broken" rather than "the controller is full." Check the module's connection count in its web diagnostics or the controller organizer before you assume the network is at fault.
Two things follow from a finite budget:
- One SCADA server holding a small number of connections and reading many tags per connection is far better than many clients each holding connections. Consolidate reads through a single OPC/driver server where you can, and let downstream clients read from that server, not from the PLC directly.
- Do not point three independent SCADA nodes, a reporting tool, and an engineer's laptop with RSLinx all at the same EN2T and expect it to absorb them.
Read the array, not 200 atomic tags
The single biggest performance mistake is configuring 200 individual atomic tags and letting the driver issue 200 separate CIP reads. Every read is a request/response round trip. The controller can answer them, but you are paying latency per tag.
CIP gives you two ways out, and good drivers use both:
- Multiple Service Packet (service 0x0A) batches several tag reads into one CIP request. Instead of 50 round trips you issue one request carrying 50 embedded read services. Most competent Logix drivers do this automatically; the knob you see is often "tags per request" or "optimize reads."
- Read the aggregate, not the members. If the data you want lives in a UDT or an array, read the whole structure in one Read Tag Service and unpack the members in the driver. Pulling
Reactor[0]throughReactor[49]as one array read is dramatically cheaper than fifty scalar reads, because a single tag reference returns the entire block.
The design implication reaches back into the PLC program: if you know a set of values will be scraped by SCADA, group them into a contiguous array or a UDT on the controller side. A flat, scattered tag database forces the driver into atomic reads no amount of tuning fixes. This is the EtherNet/IP cousin of Modbus poll-block layout — the wire efficiency is decided by the memory layout, not the driver settings.
The 500-byte wall
An unconnected CIP message, and a standard Forward Open connection, caps the payload around 504 bytes. Batch too many tags into one Multiple Service Packet, or read one array that is too large, and the response overflows that limit. The controller answers with a CIP error — often 0x06, "Reply data too large," or a partial transfer.
Two fixes:
- Let the driver split the request. A good driver notices the ceiling and breaks a large batch into several requests automatically. If yours doesn't, cap tags-per-request manually.
- Use a Large Forward Open (connected messaging with an extended connection size) when you genuinely need to move big structures, such as a several-kilobyte UDT read in one shot. This is a driver/module capability, not something every device supports — confirm before you rely on it.
If you see intermittent failures that correlate with how many tags changed at once rather than which tags, suspect the size wall before you suspect the network.
Tag scope will waste a morning
Logix tags come in two scopes, and this trips up nearly everyone the first time. Controller-scoped tags are global and a SCADA client can reference them by name directly. Program-scoped tags belong to a specific program and are invisible unless you address them with the full path: Program:MainProgram.Motor_Run, not Motor_Run.
Configure a program-scoped tag as if it were global and the read fails with a path/segment error that reads like a typo. When a tag that plainly exists in the controller comes back as not found, check its scope before you check your spelling. As a habit, expose anything SCADA needs as controller-scoped, or at least standardize the Program: prefix in your tag database so it is consistent.
RPI is not your setting — until it is
For pure Class 3 polling, there is no RPI; your poll rate is whatever the SCADA scan class is set to, same as any other driver, and it should be matched to how fast the value actually changes — sub-second for a fast interlock, several seconds for a tank level. Don't poll everything at 100 ms because you can.
RPI comes back into your life the moment SCADA uses produced/consumed tags or receives cyclic data — some architectures have the controller produce a data structure that a gateway or a soft-SCADA node consumes over a Class 1 connection. Then RPI applies, and it comes with the connection timeout multiplier: the connection is declared dead after RPI × multiplier with no packet, where the multiplier is typically 4, 8, 16, up to 512. An RPI of 100 ms with a multiplier of 4 drops the connection after 400 ms of silence. On a link that has occasional jitter, a multiplier that tight will flap. Loosen the multiplier before you slow the RPI when a cyclic connection keeps dropping on an otherwise healthy network.
What to check when reads go bad
- New client fails, old clients fine → connection budget on the Ethernet module. Count CIP connections, don't guess.
- A whole batch of tags goes bad together, others fine → one bad tag reference (wrong scope, renamed tag) failing the Multiple Service Packet, or the batch exceeded ~504 bytes. Shrink tags-per-request to isolate it.
- "Tag not found" on a tag you can see online → program scope. Add the
Program:path. - Reads slow but clean, PLC scan unchanged → too many atomic reads. Switch to array/UDT reads and enable request optimization.
- Cyclic/produced-tag connection flaps → timeout multiplier too tight for the link's jitter, not the RPI itself.
The mental model that keeps you out of trouble: EtherNet/IP charges you per round trip and per open connection, not per byte. Design the controller's tag layout so SCADA can read a lot in one request, hold as few connections as the architecture allows, and the protocol scales fine. Fight it tag-by-tag and you'll be back on the phone the day someone adds the fourth client.