Repository navigation
jp4 v1.4.0
[1.4.0] — 2026-05-16
v1.4 is a SemVer-minor addition over v1.3; the v1.3 public surface
is unchanged. See docs/migration-1.3-to-1.4.md
for usage examples of each new method. The v1.4 release completes
the per-entity-type read surface: counter, meter, register,
action-profile member, and action-profile group cells are now
readable through name-based, typed query builders that mirror the
shape ReadQuery already uses for table reads.
Added
- P4Info index extension for the four new entity types (commit
a280a1e) —P4Infonow indexes counters, meters, registers, and
action profiles in the same parse-loop pass that already indexes
tables and actions, with paired forward (counter(String),
meter(String),register(String),actionProfile(String)),
reverse-id (counterById(int),meterById(int),
registerById(int),actionProfileById(int)), and name-listing
(counterNames(),meterNames(),registerNames(),
actionProfileNames()) accessors. The forward accessors throw
P4PipelineExceptionwith a known-list hint on miss; the reverse
accessors returnnull, matching the convention shared with
tableInfoById/actionInfoById. - Four pipeline value types (commit
a280a1e) —
CounterInfo(name + id + unit + size),MeterInfo(name + id- unit + size; the spec's
MeterSpec.Unitexposes only
UNSPECIFIED/BYTES/PACKETS, not theBOTHshape
counters have),RegisterInfo(name + id + size — per-cell
P4DataTypeSpecis intentionally not exposed, matching the
conventionDigestEvent.datafollows forP4Data), and
ActionProfileInfo(name + id + size + max-group-size + the
table-id set the profile is referenced from).
- unit + size; the spec's
- **
P4Switch.readCounter(String)+CounterReadQueryinterfaceCounterEntryrecord** (commitde3e031) — name-based typed
read of one counter array. The query builder offers an
index(long)server-side filter, a non-default
where(Predicate)client-side filter, and the five terminals
(all/one/stream/allAsync/oneAsync).
CounterEntryis a flat record carrying the resolved counter
name, the cell index, and bothpacketCountandbyteCount;
which value is meaningful is determined by the counter's unit
throughP4Info.counter(name).unit(). The implementation
reuses the existingoutboundExecutor,awaitRead,
mapReadFailure, andreadabilityExceptioninfrastructure
verbatim, establishing the per-entity read template the v1.4
surface expands.
P4Switch.readMeter(String)+MeterReadQueryinterface +
MeterEntry/MeterConfig/MeterCounterData/
CounterDatarecords (commite29bd3e) — name-based typed
read of one meter array.MeterEntryis a nested record
(meter name, index,MeterConfig,MeterCounterData); the
shape mirrors the P4RuntimeMeterEntryproto directly. The
nestedMeterConfigcarriescir,cburst,pir,pburst,
andeburst— the last was added in P4Runtime 1.4.0 and is
only used by srTCM meters; for trTCM meters or for devices that
predate the addition it surfaces as zero.MeterCounterData
groups the per-color cumulative counters (green / yellow / red)
defined by RFC 2697 / RFC 2698; the message itself was added in
P4Runtime 1.4.0.CounterDatais a small two-field nested
helper (packetCount,byteCount) used only inside
MeterCounterData;CounterEntrydeliberately does not share
it because a counter cell carries a single counter datum
whereas a meter cell carries three.P4Switch.readRegister(String)+RegisterReadQuery
interface +RegisterEntryrecord (commitdd152cf) —
name-based typed read of one register array.RegisterEntry
is a three-field record (register name, index,Bytes data)
whosedatais the serialised bytes of the wirep4.v1.P4Data
proto — that is, whatproto.getData().toByteArray()returns,
not whatproto.getData().getBitstring()returns. This matches
the conventionDigestEvent.dataalready follows and the
contractRegisterInfo's javadoc promised ina280a1e.
Consumers decode via
P4Data.parseFrom(entry.data().toByteArray())and access the
appropriate oneof variant; for the commonbit<W>/int<W>
register the field is.getBitstring(). Typed P4Data
unwrapping is held for a future v1.x release.- **
P4Switch.readActionProfileMember(String)and
readActionProfileGroup(String)+ their
ActionProfileMemberReadQueryand
ActionProfileGroupReadQueryinterfaces + three records
(ActionProfileMember,ActionProfileGroup,WeightedMember)- new
ActionInstance.of(String, Map<String, Bytes>)factory**
(commit6e43a4b) — name-based typed read of both halves of
the action-profile entity family. Each query builder offers a
server-side id filter (memberId(long)andgroupId(long)
respectively), a non-defaultwhere(Predicate), and the five
terminals.ActionProfileMemberreuses the existing
ActionInstancevalue type for its action; the new public
staticActionInstance.offactory is the smallest surface
addition that lets the read path build the record without
going through theTableEntryBuilderchain.WeightedMember
carriesmemberId,weight, and a nullableBytes watchPort
whose null surface covers both an unsetwatch_kindoneof and
the deprecatedwatchint32 path; a controller that needs the
deprecated path can parse the wire proto directly.
- new
- BMv2 integration tests for the new read surfaces (commit
1199952) — a dedicatedcounters_meters_registers_groups.p4
fixture declares all four indirect features (counter, meter,
register, action_selector) in one pipeline so a single BMv2
spawn amortises across the five read API families.
CountersMetersRegistersGroupsIntegrationTestreads counter,
meter, register, action-profile member, and action-profile
group cells against a realsimple_switch_grpcinstance.
Two BMv2-shape findings shape the test code: first,
simple_switch_grpc1.15.1 returnsUNIMPLEMENTEDfor the
RegisterEntryread RPC, so the register integration test
catches that status code and skips through
Assumptions.assumeTrueuntil BMv2 adds support — the unit
test inP4SwitchReadRegisterTestalready covers the jp4
read path end-to-end against the gRPC fake; second, P4Runtime
1.3+ canonical-bytestring encoding strips leading zero bytes,
so a 9-bit port value of 5 sent to BMv2 as{0x00, 0x05}
round-trips as a single-byte{0x05}on the read side, and
the action-profile tests send the canonical form to match.