Ethernet · Module 5
Payload, Padding and Minimum Frame Size
The 64-octet minimum is a round-trip propagation time across a shared segment, converted to bits — a constraint whose mechanism full duplex removed and whose cost every frame still pays, in padding that only the length field distinguishes from data.
Chapter 5.5 §7 reconciled a declared length against a received octet count and found the two are not expected to be equal. The excess is padding, and the check treated padding as explicable only up to a floor — a floor it took as a parameter and did not justify.
This chapter justifies it, and the justification comes from outside the frame format entirely.
The number is 64 octets, and nothing about frame structure produces it. It is not derived from address size, or from a useful payload minimum, or from any property of the data being carried. It is a distance, converted into time, converted into bits.
A station on a shared medium had to still be transmitting when the far end's collision signal came back, or it would finish, believe it had succeeded, and never learn otherwise. That round trip across a maximum-length segment — Chapter 1.2's slot time — sets a minimum transmission duration, and a minimum duration at a fixed rate is a minimum size.
That mechanism is gone. Chapter 1.5 removed collisions from the modern link entirely. The floor stayed.
1. Scope — What This Chapter Owns
Chapter 1.2 owns the derivation of slot time — why a station must transmit for a round trip, how segment length and repeater count enter, and why the answer came out at 512 bit times. This chapter takes that number as given and follows what it did to the frame.
Chapter 5.5 owns the length/type field and built the check that compares a declared length against a received count. It named the floor and deferred it.
This chapter owns the floor itself and everything downstream of it: where 64 comes from, why full-duplex links still honour it, how padding is generated and removed, what a receiver can and cannot conclude from a short frame, how a tag changes the floor, and what the pad costs measured as a fraction of a link's capacity.
It does not own: the maximum frame size, which is a separate argument with separate consequences — Chapter 5.7 takes it. Nor the FCS that follows the pad, which Chapter 5.8 takes. Nor the interframe gap, which is the other inherited quantity and belongs to Chapter 5.9.
The question this chapter answers that its neighbours do not: why does a frame carrying four octets of data occupy sixty-four, and what must a receiver do so that the other sixty are not mistaken for content?
2. Where 64 Comes From, and Why It Is Not a Frame-Format Number
Work the derivation in the order it actually happened, because the order is what shows that the frame format was the output.
Start with a distance. A shared segment has a maximum end-to-end extent, fixed by signal attenuation and by the number of repeaters permitted between any two stations.
Convert it to a time. A signal takes some propagation delay to cross that distance, and a collision fragment takes the same time to come back. The worst case is a station at one end and a station at the other, so the quantity that matters is the round trip, plus the delay each repeater adds in both directions.
Convert the time to bits. At a fixed signalling rate, a duration is a bit count. Chapter 1.2 shows this landing at 512 bit times with margin, and 512 bits is 64 octets.
Now, and only now, does the frame format enter. A transmitting station must still be sending when the fragment arrives, so its frame must be at least 64 octets long. The frame already carried 18 octets of unavoidable structure — two addresses at six octets each, the length/type field at two, and the frame check sequence at four. Subtract, and the client-data region has a floor of 46 octets.
3. Full Duplex Removed the Reason and Kept the Floor
Chapter 1.5 is unambiguous: on a full-duplex link there are no collisions, no deferral, no backoff, and no slot time. The mechanism that produced the floor does not exist.
The floor is still enforced, by both ends, on every frame. A transmitter pads short frames; a receiver treats a frame below 64 octets as invalid. Neither is defending against anything.
Three reasons it stayed, and only the third is a good one.
Interoperability of the frame, not the link. A frame does not stay on one link. It is received by a switch and forwarded onto another, and Chapter 2.7 established that forwarding does not rewrite the frame's contents. If any segment anywhere in the path might be half-duplex, a frame shorter than 64 octets can be created on a full-duplex link and become undetectable on a shared one. The floor is a property of the frame format, and the frame format is shared by links that do not share the property that motivated it.
Every receiver already implements it. Removing a minimum is not backward-compatible in the direction that matters: a new transmitter emitting 40-octet frames is talking to receivers that discard them as runts. The change would have to happen at every receiver first, which is the update-the-installed-base problem Chapter 5.5 §2 showed the length/type resolution deliberately avoiding.
And the good reason: shortness now means something else. A frame below the floor is no longer a collision fragment — but it is still, reliably, damage. Truncation in a buffer, a link that dropped mid-frame, a transmitter that terminated early. The floor stopped being a defence and became a detector, and Section 8's classifier is built on exactly that repurposing.
So the honest summary is that the constraint outlived its cause and acquired a new one. That is not unusual in long-lived standards, and it is worth recognising as a distinct situation from a constraint that is simply obsolete — because the second can be removed and the first cannot.
4. Padding Is Not Data, and One Field Separates Them
On the wire the two regions are indistinguishable. There is no delimiter, no length prefix inside the payload, no change of encoding. The pad begins wherever the client's data stopped, and nothing in the octet stream marks the point.
So the boundary is carried out of band, in the length field, and this produces an asymmetry that catches designs out:
- A length-form frame carries the boundary. The field says how many octets are the client's, the rest of the region is pad, and stripping is arithmetic.
- A type-form frame does not. Chapter 5.5 showed the field holding a protocol identifier instead, which says nothing about extent. The MAC cannot strip the pad, because it does not know where it starts.
What happens in the second case is the part worth stating plainly: the pad is delivered. The MAC hands up the whole 46-octet region, and something above — the protocol identified by that very type field — has its own length field and truncates to it. IPv4 and IPv6 both carry one; that is how it works in practice.
Which means the layering is doing real work here and can be got wrong in one specific way. A MAC that tries to be helpful and strips a "probably pad" tail from a type-form frame is guessing, and Chapter 2.3's rule says it must not — it does not know the payload's format and therefore cannot know where the payload ends. The correct behaviour on a type-form frame is to deliver the pad and let the client discard it, which looks like sloppiness and is the only decision available to a layer that must not inspect what it carries.
5. RTL 1 — Generating the Pad Without Losing the Boundary
// SYNTHESIZABLE.
//
// Appends pad to reach the frame floor, and -- in the same act -- produces
// the length value that tells the far end where the client's data stopped.
//
// The two must come from ONE count. A design that computes the length in
// one place and the pad in another has two representations of the same
// boundary and no mechanism keeping them equal; they diverge on exactly
// the frames where it matters, which are the short ones.
package frame_size_pkg;
// NORMATIVE. 512 bit times -- Chapter 1.2's slot time, expressed in
// octets. Not a frame-format constant: a propagation measurement.
localparam int unsigned MIN_FRAME_OCTETS = 64;
// DA(6) + SA(6) + Length/Type(2) + FCS(4). Everything a frame carries
// whatever its payload.
localparam int unsigned FIXED_OVERHEAD = 18;
// 64 - 18. The floor on the client-data region, and the number that
// makes a one-octet transfer cost forty-six.
localparam int unsigned MIN_CLIENT = MIN_FRAME_OCTETS - FIXED_OVERHEAD; // 46
endpackage
module pad_generator
import frame_size_pkg::*;
#(
// Value written into pad octets. A PARAMETER, deliberately -- Section 13
// explains why a design must not assert this is zero even though almost
// every implementation makes it zero.
parameter logic [7:0] PAD_VALUE = 8'h00
) (
input logic clk,
input logic rst_n,
input logic frame_start,
// How many octets the client will supply. Known before transmission
// because a MAC cannot begin a frame it cannot finish.
input logic [10:0] client_octets,
input logic is_length_form,
input logic cli_valid,
input logic [7:0] cli_data,
input logic cli_last,
output logic tx_valid,
output logic [7:0] tx_data,
output logic tx_last,
output logic tx_is_pad, // for instrumentation only
// The boundary, emitted with the frame. Meaningful only in length form.
output logic emit_length_valid,
output logic [10:0] emit_length,
output logic [10:0] pad_appended
);
typedef enum logic [1:0] { P_IDLE, P_DATA, P_PAD, P_DONE } p_e;
p_e state_q;
logic [10:0] sent_q;
logic [10:0] target_q;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_q <= P_IDLE;
sent_q <= '0;
target_q <= '0;
tx_valid <= 1'b0;
tx_data <= '0;
tx_last <= 1'b0;
tx_is_pad <= 1'b0;
emit_length_valid <= 1'b0;
emit_length <= '0;
pad_appended <= '0;
end else begin
tx_valid <= 1'b0;
tx_last <= 1'b0;
tx_is_pad <= 1'b0;
emit_length_valid <= 1'b0;
case (state_q)
P_IDLE: if (frame_start) begin
state_q <= P_DATA;
sent_q <= '0;
// ONE decision, made once: how big the client-data region will
// be. The pad count and the length value are both read off it.
target_q <= (client_octets < 11'(MIN_CLIENT))
? 11'(MIN_CLIENT) : client_octets;
// The length is the CLIENT's count, never the target. Emitting
// the target here is the single most damaging bug in this
// module: the frame becomes self-consistent and the receiver
// delivers 46 octets for a 3-octet transfer, with no error
// anywhere.
emit_length <= client_octets;
emit_length_valid <= is_length_form;
pad_appended <= (client_octets < 11'(MIN_CLIENT))
? (11'(MIN_CLIENT) - client_octets) : 11'd0;
end
P_DATA: if (cli_valid) begin
tx_valid <= 1'b1;
tx_data <= cli_data;
sent_q <= sent_q + 1'b1;
if (cli_last) begin
if ((sent_q + 1'b1) >= target_q) begin
tx_last <= 1'b1;
state_q <= P_DONE;
end else begin
state_q <= P_PAD;
end
end
end
P_PAD: begin
tx_valid <= 1'b1;
tx_data <= PAD_VALUE;
tx_is_pad <= 1'b1;
sent_q <= sent_q + 1'b1;
if ((sent_q + 1'b1) >= target_q) begin
tx_last <= 1'b1;
state_q <= P_DONE;
end
end
P_DONE: state_q <= P_IDLE;
default: state_q <= P_IDLE;
endcase
end
end
endmoduleClassification: synthesizable.
What it teaches: that the length value and the pad count are two readings of one decision, and the decision is made once, at frame start, from client_octets. The failure this prevents is subtle because the resulting frame is internally consistent: emit target_q as the length instead of client_octets and the frame declares 46, carries 46, passes Chapter 5.5's extent check with zero pad, and delivers 43 octets of garbage to a peer that has no way to know.
Deliberately simplified: client_octets is known up front. A store-and-forward transmit path has it; a cut-through one does not and must either buffer to the floor before starting or defer the length until the count is known — which is one of several reasons cut-through transmit paths are harder than they look.
Production implication: tx_is_pad exists for Section 12's monitor and for nothing else — it is not a delivery qualifier. A downstream block that used it to suppress octets would be re-deriving the boundary from a signal instead of from the length field, which reintroduces the two-representations problem this module exists to avoid.
6. RTL 2 — Removing the Pad, and Refusing To Guess
// SYNTHESIZABLE.
//
// Strips pad on the receive side, and the module's real content is the
// case where it MUST NOT.
//
// length form -> the boundary is carried. Strip arithmetically.
// type form -> the boundary is NOT carried. Deliver everything and
// say so, because guessing is worse than delivering.
//
// The temptation is to trim a run of trailing zeros in the type-form case.
// It is wrong twice: the pad is not required to be zero (Section 13), and
// a payload is entitled to END in zeros. A MAC that trims has silently
// truncated a client's data with no error and no counter.
module pad_stripper
import frame_size_pkg::*;
(
input logic clk,
input logic rst_n,
input logic frame_start,
input logic is_length_form,
input logic [10:0] declared_length,
input logic rx_valid,
input logic [7:0] rx_data,
input logic rx_last,
output logic cli_valid,
output logic [7:0] cli_data,
output logic cli_last,
// High for the whole frame when the pad could not be removed here. The
// client is being handed the full region and is expected to bound the
// payload from its own header.
output logic pad_not_stripped,
output logic [10:0] stripped_octets,
// The frame declared more than it delivered: Chapter 5.5's short frame,
// seen from the stripper's side.
output logic truncated
);
logic [10:0] seen_q;
logic armed_q;
// The one comparison that does the stripping. Note it is against the
// DECLARED length, never against a pattern in the data.
wire in_client_data = (seen_q < declared_length);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
seen_q <= '0;
armed_q <= 1'b0;
cli_valid <= 1'b0;
cli_data <= '0;
cli_last <= 1'b0;
pad_not_stripped <= 1'b0;
stripped_octets <= '0;
truncated <= 1'b0;
end else begin
cli_valid <= 1'b0;
cli_last <= 1'b0;
truncated <= 1'b0;
if (frame_start) begin
seen_q <= '0;
armed_q <= is_length_form;
pad_not_stripped <= !is_length_form;
stripped_octets <= '0;
end else if (rx_valid) begin
seen_q <= seen_q + 1'b1;
if (!armed_q) begin
// Type form: everything goes up, pad included, and the flag says
// so. This is not a degraded mode -- it is the correct behaviour
// for a layer that must not parse what it carries.
cli_valid <= 1'b1;
cli_data <= rx_data;
cli_last <= rx_last;
end else if (in_client_data) begin
cli_valid <= 1'b1;
cli_data <= rx_data;
// The client's last octet is the one at declared_length-1, which
// is NOT the frame's last octet on a padded frame.
cli_last <= ((seen_q + 1'b1) == declared_length);
end else begin
stripped_octets <= stripped_octets + 1'b1;
end
if (rx_last && armed_q && ((seen_q + 1'b1) < declared_length))
truncated <= 1'b1;
end
end
end
endmoduleClassification: synthesizable.
What it teaches: that cli_last and rx_last are different events on a padded frame, and conflating them is the standard bug. The client's data ends at declared_length; the frame ends at the floor. A stripper that raises cli_last on rx_last delivers the pad with the data and marks the pad's final octet as the client's — so the client sees the right start, the wrong length, and no indication that anything went wrong.
Deliberately simplified: one octet per cycle. A wide datapath must handle a boundary that falls mid-word, which is a byte-enable problem rather than a new decision.
Production implication: pad_not_stripped is asserted for the entire frame rather than pulsed, because it describes a property of this frame's delivery contract, not an event within it. A client receiving a type-form frame needs to know before it processes the first octet that the tail is unreliable — and a pulse at frame end arrives after the client has already decided how much to keep.
7. What a Receiver Cannot Conclude From a Frame's Extent
It is worth stating the negative results directly, because each one is a conclusion designs draw anyway.
A 64-octet frame does not mean 46 octets of data. It means the client-data region was at least at the floor. Anywhere from 0 to 46 of those octets are the client's, and only the length field distinguishes them.
A frame larger than 64 octets does not mean it is unpadded. Padding lifts a frame to the floor, so any frame above it was already there — but that says nothing about a tagged frame, where Section 9 shows the floor moving.
A run of zeros at the end of a frame does not mean padding. The pad's value is not specified by the MAC standard (Section 13), and a payload may legitimately end in zeros. Both directions of this inference fail: zeros that are not pad, and pad that is not zeros.
A type-form frame's payload extent cannot be determined at this layer at all. Not approximately, not usually — the information is not present. Any answer a MAC produces is a guess about a format it is forbidden to parse.
And the one positive result, which is what Section 8 is built on: a frame below the floor is unambiguously wrong. Nothing conforming produces one. That is a rare thing in a receive path — a conclusion available from extent alone, with no field to consult and no interpretation to get wrong.
8. RTL 3 — Two Different Shortnesses, and the Bit That Separates Them
A frame can be short in two unrelated ways, and a single "runt" counter merges a link problem with a peer conformance problem.
// SYNTHESIZABLE.
//
// Three populations, three causes, three responses:
//
// FRAGMENT -- below the floor, check sequence BAD.
// Truncated in transit, or (on a shared medium) a
// collision fragment. A LINK problem.
//
// UNDERSIZED -- below the floor, check sequence GOOD.
// A peer emitted it that way and computed a correct
// check over it. Nothing damaged this frame; the
// transmitter did not pad. A PEER CONFORMANCE problem,
// and no amount of cable replacement will fix it.
//
// SHORT-DECLARED-- at or above the floor, but the length field promises
// more client octets than arrived. Chapter 5.5's short
// frame: the frame is well formed and DISHONEST.
//
// A single counter over all three is the reason "we see runts" is a
// diagnosis nobody can act on.
module runt_classifier
import frame_size_pkg::*;
#(
parameter int unsigned CNT_W = 32
) (
input logic clk,
input logic rst_n,
input logic clear,
input logic frame_done,
input logic [13:0] frame_octets, // whole frame, FCS included
input logic fcs_ok,
input logic is_length_form,
input logic [10:0] declared_length,
input logic [10:0] client_octets_rx, // what the stripper actually saw
output logic is_fragment,
output logic is_undersized,
output logic is_short_declared,
output logic [CNT_W-1:0] c_fragment,
output logic [CNT_W-1:0] c_undersized,
output logic [CNT_W-1:0] c_short_declared,
// Smallest frame ever seen. Survives `clear`, because the extreme is a
// property of what this link has carried, not of a measurement window.
output logic [13:0] smallest_seen,
output logic smallest_valid
);
wire below_floor = (frame_octets < 14'(MIN_FRAME_OCTETS));
function automatic logic [CNT_W-1:0] bump(input logic [CNT_W-1:0] v);
bump = (&v) ? v : (v + 1'b1);
endfunction
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
is_fragment <= 1'b0;
is_undersized <= 1'b0;
is_short_declared <= 1'b0;
c_fragment <= '0;
c_undersized <= '0;
c_short_declared <= '0;
smallest_seen <= '1;
smallest_valid <= 1'b0;
end else begin
is_fragment <= 1'b0;
is_undersized <= 1'b0;
is_short_declared <= 1'b0;
if (clear) begin
c_fragment <= '0;
c_undersized <= '0;
c_short_declared <= '0;
// smallest_seen deliberately survives.
end
if (frame_done) begin
if (!smallest_valid || (frame_octets < smallest_seen)) begin
smallest_seen <= frame_octets;
smallest_valid <= 1'b1;
end
if (below_floor) begin
// The check sequence is what splits these, and it is the only
// thing that can: the two frames are otherwise identical.
if (fcs_ok) begin
is_undersized <= 1'b1;
c_undersized <= bump(c_undersized);
end else begin
is_fragment <= 1'b1;
c_fragment <= bump(c_fragment);
end
end else if (is_length_form && (client_octets_rx < declared_length)) begin
is_short_declared <= 1'b1;
c_short_declared <= bump(c_short_declared);
end
end
end
end
endmoduleClassification: synthesizable.
What it teaches: that a correct check sequence over a malformed frame is diagnostic information, not a contradiction. The instinct is to treat any short frame as damage, and damage is what a bad check sequence means. A good one means the frame arrived exactly as sent — so the fault is at the sender, and every hour spent on cables, connectors and optics is wasted. The same octet count, split by one bit, sends the investigation to two different buildings.
Deliberately simplified: it consumes fcs_ok as an input. Where that signal comes from and precisely what it covers is Chapter 5.8, and the dependency is worth noticing — this classifier's central distinction is only available because a check exists that spans the whole frame.
Production implication: smallest_seen survives clear for the same reason Chapter 5.4's worst broadcast rate does. A counter answers how often; an extreme answers how bad, and the two are cleared on different schedules. A link whose smallest frame ever is 64 has never seen a runt; one whose smallest is 17 has a specific event to explain, and the count of similar events since the last clear says nothing about it.
9. A Tag Moves the Floor, and the Standard Gives Two Answers
Chapter 5.5 §8 showed a tag displacing the length/type field. It also changes the arithmetic in this chapter, in a way that produces a genuine interoperability trap.
The frame floor does not move: it is still 64 octets. But the fixed overhead grew by four, so the client-data floor drops from 46 to 42. A tagged frame with 42 octets of client data needs no padding at all; an untagged one with 42 needs four.
Now follow a tagged 64-octet frame through a device that removes the tag. Four octets come out, and the frame is 60 — below the floor it must satisfy on the next link. The device has to pad it back up, which means re-running the pad logic on the egress side of a forwarding path, on a frame it did not originate.
The standard permits an alternative, and it is the interesting one. A transmitter emitting a tagged frame may pad it to 68 octets rather than 64 — keeping the client-data region at 46 as though the tag were not there — precisely so that removing the tag yields a 64-octet frame that needs no further work.
Read that as a design pattern rather than a special case. The cost is four octets on frames that are already the least efficient on the link. The purchase is that a downstream transformation becomes size-preserving at the floor, so the device performing it does not need pad logic at all. A small unconditional cost at the source, in exchange for removing a conditional behaviour from every device downstream — and conditional behaviours at a floor are exactly where interoperability failures live.
10. RTL 4 — The Floor as a Computed Quantity
// SYNTHESIZABLE.
//
// The client-data floor is not a constant once tags exist, so it must be
// COMPUTED per frame rather than parameterised per design.
//
// Two policies, and the parameter chooses:
//
// FLOOR_POLICY_MIN -- pad only to the 64-octet frame floor. Fewest
// octets on the wire; a downstream tag removal must
// repad.
// FLOOR_POLICY_POP -- pad as though the tags were absent (up to 68 for
// one tag). Four octets more; downstream tag
// removal becomes size-safe.
//
// The parameter is exposed rather than chosen here because the right
// answer depends on what is downstream, which this module cannot know.
module tagged_floor_adjust
import frame_size_pkg::*;
#(
parameter bit POP_SAFE = 1'b0,
// Tags this design will account for. Beyond this the frame is refused
// rather than sized by a guess -- Chapter 5.5 §9's bounded-parse rule
// applied to an arithmetic problem instead of a parsing one.
parameter int unsigned MAX_TAGS = 2,
parameter int unsigned TAG_OCTETS = 4
) (
input logic clk,
input logic rst_n,
input logic req_valid,
input logic [2:0] tags_present,
output logic rsp_valid,
output logic rsp_ok,
// Floor on the CLIENT-DATA region for this frame.
output logic [10:0] client_floor,
// Floor on the whole frame, which is what a receiver checks.
output logic [13:0] frame_floor
);
// Overhead grows with each tag; the client-data floor shrinks by the
// same amount, because the FRAME floor is what is fixed.
wire [10:0] tag_octets = 11'(tags_present) * 11'(TAG_OCTETS);
wire [10:0] shrunk = 11'(MIN_CLIENT) - tag_octets;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rsp_valid <= 1'b0;
rsp_ok <= 1'b0;
client_floor <= 11'(MIN_CLIENT);
frame_floor <= 14'(MIN_FRAME_OCTETS);
end else begin
rsp_valid <= req_valid;
if (req_valid) begin
if (tags_present > 3'(MAX_TAGS)) begin
// Refuse rather than compute. A negative floor is what an
// unbounded version produces, and an unsigned subtraction turns
// that into an enormous positive one -- a frame padded to
// thousands of octets, from one wrap.
rsp_ok <= 1'b0;
client_floor <= 11'(MIN_CLIENT);
frame_floor <= 14'(MIN_FRAME_OCTETS);
end else begin
rsp_ok <= 1'b1;
if (POP_SAFE) begin
// Size as though the tags were not there. The frame floor
// rises with each tag; the client floor stays at 46, so
// removing a tag lands exactly on the 64-octet floor.
client_floor <= 11'(MIN_CLIENT);
frame_floor <= 14'(MIN_FRAME_OCTETS) + 14'(tag_octets);
end else begin
client_floor <= shrunk;
frame_floor <= 14'(MIN_FRAME_OCTETS);
end
end
end
end
end
endmoduleClassification: synthesizable.
What it teaches: that a floor computed by subtraction needs its bound checked before the subtraction, not after. MIN_CLIENT - tag_octets is fine for zero, one or two tags and wraps for twelve. Unsigned wrap does not produce a small number or a negative one — it produces a floor near 2048, and the transmitter dutifully pads every frame to it. The symptom is enormous frames on a link that should be carrying small ones, which reads as a payload problem and is an arithmetic one.
Deliberately simplified: a fixed four octets per tag. Real deployments see one tag size in practice, and the parameter exists so the module does not encode the assumption silently.
Production implication: POP_SAFE is exposed rather than decided because the right answer depends on a device this module cannot see. A NIC whose frames terminate at a directly attached switch that pops tags should set it; one on a link where nothing removes tags is paying four octets per short frame for nothing. A parameter is the correct representation of a decision that belongs to the system integrator — and hard-coding either value is a design that is wrong in half of its deployments and silent about which half.
11. What the Floor Costs, Measured Properly
The floor's cost is usually stated as "small frames are inefficient", which is true and not actionable. The measurable version is more useful and more alarming.
Count everything the wire carries for one minimum frame:
| Region | Octets |
|---|---|
| preamble and start delimiter | 8 |
| addresses and length/type | 14 |
| client data | n |
| pad | 46 − n |
| frame check sequence | 4 |
| interframe gap | 12 |
| total wire occupancy | 84 |
Illustrative, from that table: a frame carrying one octet of client data occupies 84 octet times. The useful fraction is 1/84 — about 1.2%. Even at the full 46 octets, the useful fraction is 46/84, about 55%, because preamble, header, check sequence and gap are all still there.
Now express the same thing as a rate, which is the form that changes decisions. On a link running at line rate with minimum-size frames back to back, the frame rate is line rate divided by 84 octets — so a 1 Gb/s link carries roughly 1.49 million minimum frames per second, an illustrative figure that follows directly from 84 × 8 = 672 bits per frame slot.
Two consequences, and neither is about bandwidth.
The packet rate, not the bit rate, sizes the receive path. Every frame costs a lookup, a filter decision, an interrupt or descriptor, a buffer. Those costs are per frame, so a link saturated with minimum-size frames imposes roughly twenty times the per-frame work of one saturated with 1500-octet frames at the same bit rate. A receive path sized by bandwidth is undersized by that factor.
And the pad is bandwidth that no accounting layer sees. It is inside the frame, so it is counted as payload by every counter that counts frame octets. A link that is 40% pad reports as fully utilised while carrying 60% of the data it appears to. Section 12 measures it, because nothing else in the system can.
12. RTL 5 — Measuring the Pad, Because Nothing Else Can
// SYNTHESIZABLE INSTRUMENTATION.
//
// Answers a question no other counter in the system can:
//
// of the octets this link carried, how many were the floor's, and
// how many were the client's?
//
// Every conventional octet counter counts pad as payload, because pad is
// inside the frame. So a link that is heavily padded reports full
// utilisation while delivering a fraction of that in data, and the gap is
// invisible from every direction except this one.
module padding_composition_monitor
import frame_size_pkg::*;
#(
parameter int unsigned CNT_W = 40,
parameter int unsigned WINDOW = 1_000_000,
parameter int unsigned WIN_W = $clog2(WINDOW + 1)
) (
input logic clk,
input logic rst_n,
input logic clear,
input logic frame_done,
input logic [13:0] frame_octets,
input logic [10:0] pad_octets,
input logic was_padded,
output logic [CNT_W-1:0] total_octets,
output logic [CNT_W-1:0] pad_total,
output logic [CNT_W-1:0] frames_total,
output logic [CNT_W-1:0] frames_padded,
// Per-window snapshot. A RATIO is only meaningful over an interval, and
// a free-running pair of counters cannot express "right now".
output logic [CNT_W-1:0] win_octets,
output logic [CNT_W-1:0] win_pad,
output logic win_valid,
// Worst window seen. Survives `clear`, like Section 8's smallest frame.
output logic [CNT_W-1:0] worst_pad_permille
);
logic [WIN_W-1:0] win_q;
logic [CNT_W-1:0] wo_q, wp_q;
function automatic logic [CNT_W-1:0] add(input logic [CNT_W-1:0] v,
input logic [CNT_W-1:0] d);
add = (v > ({CNT_W{1'b1}} - d)) ? {CNT_W{1'b1}} : (v + d);
endfunction
// Per mille rather than per cent, and integer rather than fractional.
// A design that reports a percentage loses the difference between 0.4%
// and 0.04% pad -- which is exactly the range in which a link is fine.
wire [CNT_W-1:0] win_permille =
(wo_q == '0) ? '0 : ((wp_q * 1000) / wo_q);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
total_octets <= '0;
pad_total <= '0;
frames_total <= '0;
frames_padded <= '0;
win_q <= '0;
wo_q <= '0;
wp_q <= '0;
win_octets <= '0;
win_pad <= '0;
win_valid <= 1'b0;
worst_pad_permille <= '0;
end else begin
win_valid <= 1'b0;
if (clear) begin
total_octets <= '0;
pad_total <= '0;
frames_total <= '0;
frames_padded <= '0;
// worst_pad_permille deliberately survives.
end else if (frame_done) begin
total_octets <= add(total_octets, CNT_W'(frame_octets));
pad_total <= add(pad_total, CNT_W'(pad_octets));
frames_total <= add(frames_total, CNT_W'(1));
if (was_padded) frames_padded <= add(frames_padded, CNT_W'(1));
wo_q <= add(wo_q, CNT_W'(frame_octets));
wp_q <= add(wp_q, CNT_W'(pad_octets));
end
if (win_q == WIN_W'(WINDOW - 1)) begin
win_octets <= wo_q;
win_pad <= wp_q;
win_valid <= 1'b1;
if (win_permille > worst_pad_permille) worst_pad_permille <= win_permille;
wo_q <= '0;
wp_q <= '0;
win_q <= '0;
end else begin
win_q <= win_q + 1'b1;
end
end
end
endmoduleClassification: synthesizable instrumentation.
What it teaches: that frames_padded and pad_total answer different questions and a design needs both. The frame count says how many transfers were below the floor — a property of the traffic's shape. The octet total says how much capacity the floor consumed — a property of the link's economics. A workload of tiny frames scores high on both; a workload with a few one-octet frames among many large ones scores high on the first and negligibly on the second, and treating those as the same finding sends the investigation to the wrong layer.
Deliberately simplified: integer per-mille, computed with a divide at the window boundary. A divider once per window is affordable in a way that a divider per frame is not, and the placement is the design decision rather than the arithmetic.
Production implication: this monitor is the only thing in the system that can say a link is fully utilised and mostly idle in the useful sense. The interface counters, the switch's port statistics, and the driver's byte counts all count pad as data, because from their vantage point it is indistinguishable from data — which is the same reason Section 4 gave for why the boundary has to be carried in a field. Instrumentation inherits the ambiguities of the format it observes, and escaping them requires a signal from the point where the ambiguity was resolved.
13. Assertions — The Boundary, the Floor, and One Property About Content
// ---------------------------------------------------------------------
// P1 -- THE CENTRAL PROPERTY. The emitted length is the CLIENT's octet
// count, never the padded target. Section 5's most damaging bug produces
// a frame that is internally consistent and silently wrong.
// ---------------------------------------------------------------------
property p_length_is_client_count;
@(posedge clk) disable iff (!rst_n)
(emit_length_valid) |-> (emit_length == $past(client_octets));
endproperty
a_length_is_client_count: assert property (p_length_is_client_count)
else $error("length field carries the padded size, not the client's");
// ---------------------------------------------------------------------
// P2 -- Every transmitted frame reaches the floor.
// ---------------------------------------------------------------------
property p_frame_reaches_floor;
@(posedge clk) disable iff (!rst_n)
(tx_valid && tx_last) |-> (sent_total >= 11'(MIN_CLIENT));
endproperty
a_frame_reaches_floor: assert property (p_frame_reaches_floor);
// ---------------------------------------------------------------------
// P3 -- Pad is only ever appended, never inserted. A pad octet before the
// client's last octet has corrupted the payload rather than extended it.
// ---------------------------------------------------------------------
property p_pad_only_after_data;
@(posedge clk) disable iff (!rst_n)
(tx_valid && tx_is_pad) |-> client_data_complete;
endproperty
a_pad_only_after_data: assert property (p_pad_only_after_data);
// ---------------------------------------------------------------------
// P4 -- A frame already at or above the floor is not padded at all.
// ---------------------------------------------------------------------
property p_no_pad_when_long_enough;
@(posedge clk) disable iff (!rst_n)
(frame_start && client_octets >= 11'(MIN_CLIENT)) |=> (pad_appended == '0);
endproperty
a_no_pad_when_long_enough: assert property (p_no_pad_when_long_enough);
// ---------------------------------------------------------------------
// P5 -- Pad count and length are two readings of one decision, so they
// must sum to the region size. This is the ONE relation that keeps them
// from drifting.
// ---------------------------------------------------------------------
property p_pad_plus_length_is_region;
@(posedge clk) disable iff (!rst_n)
(emit_length_valid && pad_appended != '0)
|-> ((emit_length + pad_appended) == 11'(MIN_CLIENT));
endproperty
a_pad_plus_length_is_region: assert property (p_pad_plus_length_is_region);
// ---------------------------------------------------------------------
// P6 -- RECEIVE SIDE. The client is delivered exactly the declared count
// on a length-form frame. Not the region, not the frame.
// ---------------------------------------------------------------------
property p_delivers_declared_count;
@(posedge clk) disable iff (!rst_n)
(cli_valid && cli_last && !pad_not_stripped)
|-> (delivered_count == declared_length);
endproperty
a_delivers_declared_count: assert property (p_delivers_declared_count);
// ---------------------------------------------------------------------
// P7 -- cli_last and rx_last are DIFFERENT events on a padded frame. The
// standard bug is raising the first on the second.
// ---------------------------------------------------------------------
property p_cli_last_precedes_rx_last;
@(posedge clk) disable iff (!rst_n)
(cli_last && stripped_octets_will_be_nonzero) |-> !rx_last;
endproperty
a_cli_last_precedes_rx_last: assert property (p_cli_last_precedes_rx_last);
// ---------------------------------------------------------------------
// P8 -- A type-form frame is NEVER stripped. The boundary is not present,
// so any stripping is a guess about a format this layer may not parse.
// ---------------------------------------------------------------------
property p_type_form_never_stripped;
@(posedge clk) disable iff (!rst_n)
(frame_start && !is_length_form) |=> (pad_not_stripped && stripped_octets == '0);
endproperty
a_type_form_never_stripped: assert property (p_type_form_never_stripped);
// ---------------------------------------------------------------------
// P9 -- The three shortness classes partition. A frame cannot be two of
// them, and a frame that is none of them is not short.
// ---------------------------------------------------------------------
property p_shortness_classes_disjoint;
@(posedge clk) disable iff (!rst_n)
frame_done |=> $onehot0({is_fragment, is_undersized, is_short_declared});
endproperty
a_shortness_classes_disjoint: assert property (p_shortness_classes_disjoint);
// ---------------------------------------------------------------------
// P10 -- The check sequence is what splits fragment from undersized, so
// each class implies its own value of fcs_ok.
// ---------------------------------------------------------------------
property p_undersized_implies_good_fcs;
@(posedge clk) disable iff (!rst_n)
is_undersized |-> $past(fcs_ok);
endproperty
a_undersized_implies_good_fcs: assert property (p_undersized_implies_good_fcs);
// ---------------------------------------------------------------------
// P11 -- A short-declared frame is at or above the floor. Below it, the
// frame is a fragment or undersized and the declaration is not the story.
// ---------------------------------------------------------------------
property p_short_declared_is_full_size;
@(posedge clk) disable iff (!rst_n)
is_short_declared |-> ($past(frame_octets) >= 14'(MIN_FRAME_OCTETS));
endproperty
a_short_declared_is_full_size: assert property (p_short_declared_is_full_size);
// ---------------------------------------------------------------------
// P12 -- The computed floor never wraps. Checked as a RANGE on the
// output, because the bound test protecting it is easy to move.
// ---------------------------------------------------------------------
property p_client_floor_sane;
@(posedge clk) disable iff (!rst_n)
(rsp_valid && rsp_ok) |-> (client_floor <= 11'(MIN_CLIENT));
endproperty
a_client_floor_sane: assert property (p_client_floor_sane);
// ---------------------------------------------------------------------
// P13 -- The FRAME floor is the invariant; the client floor is derived.
// Under the minimum policy the frame floor never moves.
// ---------------------------------------------------------------------
property p_frame_floor_fixed_when_min;
@(posedge clk) disable iff (!rst_n)
(rsp_valid && rsp_ok && !POP_SAFE) |-> (frame_floor == 14'(MIN_FRAME_OCTETS));
endproperty
a_frame_floor_fixed_when_min: assert property (p_frame_floor_fixed_when_min);
// ---------------------------------------------------------------------
// P14 -- Under the pop-safe policy, removing the tags lands exactly on
// the floor. This is the property the policy exists to provide.
// ---------------------------------------------------------------------
property p_pop_safe_lands_on_floor;
@(posedge clk) disable iff (!rst_n)
(rsp_valid && rsp_ok && POP_SAFE)
|-> ((frame_floor - 14'($past(tags_present)) * 14'(TAG_OCTETS))
== 14'(MIN_FRAME_OCTETS));
endproperty
a_pop_safe_lands_on_floor: assert property (p_pop_safe_lands_on_floor);
// ---------------------------------------------------------------------
// P15 -- Pad octets never exceed the octets counted. A monitor that can
// report more pad than traffic is adding to the wrong accumulator.
// ---------------------------------------------------------------------
property p_pad_within_total;
@(posedge clk) disable iff (!rst_n)
win_valid |-> (win_pad <= win_octets);
endproperty
a_pad_within_total: assert property (p_pad_within_total);
// ---------------------------------------------------------------------
// P16 -- Extremes survive a counter clear, because they describe the link
// rather than the window.
// ---------------------------------------------------------------------
property p_extremes_survive_clear;
@(posedge clk) disable iff (!rst_n)
clear |=> ($stable(smallest_seen) && $stable(worst_pad_permille));
endproperty
a_extremes_survive_clear: assert property (p_extremes_survive_clear);
// ---------------------------------------------------------------------
// P17 -- COVERAGE. A run with no padded frame never exercised this
// chapter at all.
// ---------------------------------------------------------------------
c_padded_frame_seen: cover property (
@(posedge clk) disable iff (!rst_n) (tx_valid && tx_is_pad)
);
// ---------------------------------------------------------------------
// P18 -- COVERAGE. The exact boundary: a client supplying precisely the
// floor, which must produce NO pad and is one octet from producing some.
// ---------------------------------------------------------------------
c_exact_floor_seen: cover property (
@(posedge clk) disable iff (!rst_n)
(frame_start && client_octets == 11'(MIN_CLIENT))
);14. Verification — Twenty-Two Scenarios and the Frame That Lies About Itself
| # | Scenario | Stimulus | What must be observed |
|---|---|---|---|
| 1 | Zero-octet client transfer | client_octets = 0, length form | 46 pad octets; emit_length = 0; frame is 64 |
| 2 | One-octet transfer | client_octets = 1 | 45 pad; emit_length = 1 — not 46 (P1) |
| 3 | Exactly at the floor | client_octets = 46 | zero pad; emit_length = 46; no tx_is_pad at all (P4) |
| 4 | One below the floor | client_octets = 45 | exactly one pad octet — the smallest non-zero pad |
| 5 | One above the floor | client_octets = 47 | zero pad; frame is 65 |
| 6 | Maximum client data | client_octets = 1500 | zero pad; nothing in this module changes |
| 7 | Type-form short frame | 3 octets, type form | padded to the floor; emit_length_valid low |
| 8 | Receive, padded length form | declared 4, 46 arrive | 4 delivered; stripped_octets = 42; cli_last on the 4th |
| 9 | Receive, unpadded | declared 100, 100 arrive | 100 delivered; stripped_octets = 0 |
| 10 | Receive, type form | type 0x0800, 46 octets | all 46 delivered; pad_not_stripped high for the whole frame (P8) |
| 11 | Receive, truncated | declared 40, 20 arrive | truncated asserts; nothing beyond 20 delivered |
| 12 | cli_last timing | declared 4 in a 46-octet region | cli_last on octet 4, rx_last on octet 46 — different cycles (P7) |
| 13 | Payload ending in zeros | declared 46, last 10 octets zero | all 46 delivered — no trimming |
| 14 | Non-zero pad from a peer | declared 4, pad octets are 0xA5 | 4 delivered; pad reported by the monitor, no assertion fires |
| 15 | Fragment | 40 octets, bad check sequence | is_fragment; c_fragment increments |
| 16 | Undersized with a good check | 40 octets, good check sequence | is_undersized — a peer conformance fault, not a link fault (P10) |
| 17 | Short-declared | 64 octets, declared 60, 46 present | is_short_declared; the other two classes stay low (P9) |
| 18 | Smallest-seen tracking | a 17-octet frame, then a clear | smallest_seen = 17 survives; counters zero (P16) |
| 19 | One tag, minimum policy | tags_present = 1, POP_SAFE = 0 | client_floor = 42; frame_floor = 64 |
| 20 | One tag, pop-safe policy | tags_present = 1, POP_SAFE = 1 | client_floor = 46; frame_floor = 68 (P14) |
| 21 | Tag count over the bound | tags_present = 5, MAX_TAGS = 2 | rsp_ok low; floors held at defaults — no wrap (P12) |
| 22 | Pad composition | 1000 frames, half at the floor | win_pad / win_octets matches the constructed ratio |
15. Debugging — Short Frames, and Which Kind of Short
Symptom — a peer's application receives more data than was sent, and the extra bytes are zeros.
The classic signature of a length field carrying the padded size. Check emit_length against the client's octet count at the transmitter directly; the receiver cannot detect this, because the frame is self-consistent. If the transmitter is not accessible, the tell is in the data: the excess is exactly the difference between the client's count and 46, and it appears only on transfers below 46 octets. A transfer of 50 octets arrives correctly, which is what makes the report read as "sometimes we get extra bytes" rather than as a padding bug.
Symptom — runt counters climbing, and cable replacement changes nothing.
Read Section 8's split rather than the aggregate. If the frames are undersized — short with a good check sequence — then nothing in the transmission path damaged them; the peer emitted them that way, and the fault is in its transmit padding. If they are fragments — short with a bad check sequence — the frames were damaged after transmission, and the physical path is the right place to look. The aggregate counter cannot distinguish a defective peer from a defective cable, and both hypotheses are consistent with it.
Symptom — a link reports high utilisation, and the application throughput does not account for it.
Read win_pad against win_octets. A link that is 30% pad is delivering 70% of what its octet counters claim, and every conventional counter in the path agrees with the wrong number because pad is inside the frame. Then read frames_padded as well, because the response differs: many small transfers means the fix is batching at the application, while a few tiny frames among large ones means the pad is negligible and the throughput problem is elsewhere.
Symptom — frames are enormous on a link that should be carrying small ones.
Suspect the floor computation before suspecting the payload. Section 10's subtraction wraps if the tag bound is bypassed, producing a client floor near 2048 and a transmitter that pads every frame to it. Confirm by checking whether the frame size is constant — a wrapped floor pads everything to the same value, which no payload distribution does.
Symptom — a switch that pops tags emits frames the next hop counts as runts.
Expected behaviour with the minimum policy, and it means the tag removal is not repadding. A tagged 64-octet frame becomes 60 when four octets are removed, and 60 is below the floor. Either the popping device must repad, or the originating device must use the pop-safe policy of Section 10 and emit 68-octet tagged frames. Note which device is at fault: the one emitting runts is the one with the bug, but the cheapest fix may be at the source, and that is a system decision rather than a conformance one.
Symptom — pad octets contain recognisable fragments of other traffic.
Not a receiver bug and not a link fault. A transmitter somewhere is padding with uninitialised buffer memory, which is a real and catalogued information-disclosure class. Capture the source address and report it; do not attempt to remediate at the receiver, which cannot, and do not assert on it in RTL, for the reasons Section 13 gives at length.
16. Common Misconceptions
"64 octets is the minimum because a frame needs that much structure."
The wrong model: the number falls out of the header and trailer sizes.
What it costs: you cannot explain why full-duplex links still enforce it, why the number is 64 rather than 32 or 128, or why it did not change when the header grew by four octets for tagging. And you have no way to reason about what would have to be true for it to change.
The corrected model: it is 512 bit times, which is a round-trip propagation time across a maximum-length shared segment, converted to bits at the signalling rate. The frame format was the output of that calculation, not its input — and 46 is what remains after subtracting 18 octets of unavoidable structure.
"Padding is part of the payload."
The wrong model: the client-data region is the payload, and its whole extent belongs to the client.
What it costs: a receiver that delivers the region rather than the declared length, so every short transfer arrives with a tail of octets the sender never wrote. The application sees them as data, and the bug reports as "extra bytes", not as a padding fault.
The corrected model: the pad is inserted by the transmitting MAC and belongs to nobody. It is separated from the client's data by exactly one thing — the length field — and when the field is a type instead, that separation does not exist at this layer at all.
"Trailing zeros in a frame are padding."
The wrong model: you can find the boundary by looking at the data.
What it costs: both directions of the inference fail. A payload is entitled to end in zeros, so trimming truncates real data with no error and no counter. And the pad is not required to be zero, so a non-zero tail that is pad is delivered as data.
The corrected model: the boundary is metadata, not content. It is carried in the length field or it is not carried at all. Section 13's rejected property is what happens when a design forgets this and asserts the pad's value.
"A short frame means a bad cable."
The wrong model: runts are a physical-layer symptom.
What it costs: an investigation aimed at the link when the fault is in a peer's transmit path. Cables get replaced, optics get swapped, and the counters keep climbing because nothing on the path was ever damaging anything.
The corrected model: the check sequence splits them. A short frame with a bad check sequence was damaged in transit. A short frame with a good one was emitted that way by a peer whose padding is broken — and it is not a link problem in any sense.
"Padding costs a few bytes."
The wrong model: the overhead is the pad octets themselves.
What it costs: you size a receive path by bandwidth. A link saturated with minimum frames imposes roughly twenty times the per-frame work of one saturated with maximum frames at the same bit rate, and per-frame work is what actually runs out.
The corrected model: the cost is a frame rate, not an octet count. A minimum frame occupies 84 octet times once preamble and gap are counted, so at a fixed line rate the frame rate is fixed and high — and every lookup, filter decision and buffer is charged against it. The pad is also invisible to every octet counter in the system, so the link reports a utilisation it is not delivering.
17. Interview Reasoning
"Why is the minimum Ethernet frame 64 bytes?"
The weak answer names the header arithmetic. The answer that ends the topic runs the derivation in its real direction: a maximum segment length gives a propagation delay, the round trip of that delay is the time a station must still be transmitting to hear a collision, that time at the signalling rate is 512 bit times, and 512 bits is 64 octets — after which the frame format subtracts its 18 octets of structure to leave a 46-octet client floor. The payoff is that every term in the chain is about a shared medium, and none of them exists on a modern link.
"Full duplex has no collisions. Why do we still pad?"
The trap is to answer "legacy" and stop. The complete answer has three parts and grades on the third: frames cross links with different properties and the format is shared, so a short frame created on a full-duplex link can become undetectable elsewhere; every deployed receiver already enforces the floor, so removing it is not backward-compatible in the direction that matters; and — the good reason — shortness now reliably means damage, so the constraint stopped being a defence and became a detector.
"You see runts on a link. What do you check first?"
Not the cable. The strong answer asks for the check sequence on those frames, because it splits the population into two causes with two different owners: a bad one means damage in transit, a good one means a peer transmitted a frame that was already short — its padding is broken, and nothing about the link is wrong. Adding that a single "runt" counter cannot express this distinction, and that the third population — a full-size frame whose length field promises more than it delivered — is a different fault again, is what shows the question has been met before.
"Should you assert that padding bytes are zero?"
No, and the reason is the interesting part: a conformant implementation can violate it, because the MAC standard specifies the pad's size and not its contents. Then the two follow-ups that make the answer complete: non-zero pad from a peer is a real finding — it has been an exploited information-disclosure class, where drivers padded with uninitialised buffer memory — so the correct instrument is a monitor that names the source address, not an assertion in your own receiver that fires in the wrong device and gets disabled. And on the transmit side, where you do control it, pad with a constant.
18. Understanding Check
It is a distance converted to a time converted to bits.
A shared segment has a maximum end-to-end extent. A collision at the far end takes a round trip to come back, plus repeater delays in both directions. A transmitter must still be sending when it arrives, or it will finish, believe it succeeded, and never learn otherwise. That round trip is 512 bit times, and 512 bits is 64 octets.
The frame format enters last. Subtract the 18 octets every frame carries — two addresses, the length/type field, the check sequence — and 46 remain as the client-data floor.
It cannot be per-link because a station cannot know which link it is on. A shorter minimum is perfectly safe on a short segment and unsafe on a long one, and the property being defended is a property of the worst case in the network, not of the cable in front of this station.
And it is why the number outlived its cause. The frame travels; the segment does not. A format shared by links that no longer share the constraint keeps the constraint.
19. What's Next
The claim this chapter defended: the payload floor is inherited, and padding is what frames pay for a constraint that no longer applies to them.
64 octets is a round-trip propagation time across a shared segment, converted to bits — a measurement in metres, made once, that still shapes every frame transmitted today. Full duplex removed the collisions that produced it, and the floor stayed: partly because frames cross links that do not share the property, partly because every receiver already enforces it, and partly because shortness became a reliable indicator of damage once it stopped being a symptom of contention.
And padding is not data. It is inserted by the transmitting MAC, separated from the client's octets by the length field alone, and invisible to every counter in the system — which is why a receiver must strip by the declared count rather than by the frame's extent, must refuse to strip at all when the field is a type, and must never assume anything about what the pad octets contain.
Chapter 5.7 — MTU and Jumbo Frames takes the other end of the same axis. If the minimum is inherited from a mechanism that is gone, the maximum is a convention that was never derived from anything physical at all — and raising it is not a setting on a device but an agreement among every device on a path.
5.7 shows what a larger frame buys — the per-frame overhead this chapter measured at 84 octets, amortised over far more payload — and what it costs: a length field that cannot express the size, buffers that must grow at every hop, and a mismatch that manifests not as an error but as a black hole, in which frames of one size pass and frames of another silently do not.
The full path is on the Ethernet curriculum index.
Continue learning
Related tutorials
- Related topic
CSMA/CD, Collision Domains and Slot Time
Slot time is the parameter the whole half-duplex MAC hangs on: it bounds medium acquisition, bounds a collision fragment, and is the retransmission quantum. Deriving it from round-trip propagation plus jam is what fixes Ethernet's minimum frame size — a timing constant wearing a frame-format costume.
- Related topic
The MAC Layer
Framing, addressing, error detection, sizing, interframe gap and transmit access. Each exists because the medium is unreliable, shared, or both — and knowing which reason applies predicts exactly what full duplex deleted and what it left untouched.
- Related topic
MTU and Jumbo Frames
The minimum frame size was derived from physics; the maximum was chosen — so it can be raised by agreement, and the agreement's scope is a path enforced by devices whose scope is a link. A partial agreement produces a black hole rather than an error.
- Related topic
The Transmit Path
Framing, padding, check append and interframe gap in one datapath — and their order is forced rather than chosen, because the pad is inside the covered range and the gap is outside the frame. Plus the one event the order cannot help with.
Standards & specifications
- Governing standard
- IEEE Std 802.3 (Ethernet)(opens IEEE in a new tab)
Defines the Ethernet MAC, the media-independent interfaces and the physical-layer sublayers, including framing, access control, auto-negotiation and per-rate PHY specifications. VLAN tagging, priority and time-sensitive shaping are defined by IEEE 802.1, not by 802.3.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the Ethernet curriculum.
