Skip to content
VLSI Mentor

Ethernet · Module 7

Frame Validity — Runts, Giants and Malformed Frames

Invalid is three predicates, not one: malformed by the standard, unacceptable to this device's configuration, or valid and simply unwanted — with three owners, three kinds of evidence and three correct actions.

Chapter 7.2 produced a list of discard reasons and attributed each to a stage. It stopped short of defining them, and the definitions turn out to be the interesting part.

Because "invalid" is not one predicate. It is three, and they are routinely merged.

A frame can be malformed — the standard says it is not a well-formed frame, and every conforming device agrees. It can be unacceptable to this device — perfectly conformant, and larger than a ceiling somebody configured here. Or it can be valid and unwanted — nothing wrong with it at all, addressed to somebody else.

The three have different owners. A malformed frame is somebody's fault, usually a peer's or a link's. An unacceptable frame is usually this device's configuration, and Chapter 5.7 §6 showed that in a jumbo deployment it is overwhelmingly the common case. An unwanted frame is not a fault in any sense.

And they produce identical symptoms if a design reports them with one word.

1. Scope — What This Chapter Owns

This chapter owns the definitions and their attribution. What exactly makes a frame malformed, which limits are normative and which are local, how a frame that is not a whole number of octets is classified, and when a failing frame should be forwarded rather than dropped.

It does not rebuild the detectors. Chapter 5.6 §8 built the fragment-versus-undersized split and established that the check sequence is what separates them; Chapter 5.7 built the size classifier and the giant detector with its local-versus-standard distinction; Chapter 7.2 built the discard accounting. This chapter says what their outputs mean and adds the two cases none of them covered: alignment errors and dribble bits.

It does not own the address filter, which decides "unwanted" — that is Chapter 7.4, and this chapter needs only the fact that its verdict is not a validity verdict.

The question this chapter answers that its neighbours do not: when a frame is rejected, who is at fault — and what in the frame or the configuration tells you?

2. Three Predicates

A received frame is put to three separate questions. Is it well formed, which the standard answers and every conforming device agrees on. Is it acceptable to this device, which this device's configuration answers and two devices may answer differently. Is it wanted by this station, which the address filter answers and which is not a fault in any sense. Only the first question is about the frame itself.A received framethe same octetsWell formed?the standard answersAcceptable here?configuration answersWanted?the address filter answersA property of theframeevery device agreesA property of thisdevicetwo devices may differNot a fault at alla denominator, not anerror12
Figure 1 — the same frame put to three different questions, each answered by a different authority.

Read the bottom row, because it is the whole chapter in three cells.

A malformed frame is malformed everywhere. Send it to ten devices and all ten agree, because the predicate is evaluated against the standard and the standard does not vary. The evidence is in the octets.

An unacceptable frame is a statement about the receiver. Chapter 5.7 established a device's ceiling as configuration, so the same 9018-octet frame is fine on one device and rejected by its neighbour — and the frame is conformant in both cases. The evidence is in a parameter, not in the frame.

An unwanted frame is not a fault, and Chapter 7.2 §9 kept it out of the fault total for that reason. On a flooded segment it is most arrivals.

The failure mode is a single "errors" counter that includes all three. It rises with traffic volume because of the third, rises with a local misconfiguration because of the second, and rises with a real fault because of the first — and an operator reading it cannot tell which happened.

3. The Normative Definitions, Exactly

Four conditions are defined by the standard rather than by a device, and the precision matters because two of them are defined against each other.

A frame below the minimum. Below 64 octets — Chapter 5.6's floor, which is a round-trip propagation time in disguise. Nothing conforming produces one.

A frame above the maximum. Above the applicable standard maximum — 1518 basic, 1522 with one tag, 2000 for an envelope frame, per Chapter 5.7 §3. This is the normative ceiling and it is not the ceiling most devices enforce.

A frame that fails its check sequence and is a whole number of octets is an FCS error.

A frame that fails its check sequence and is not a whole number of octets is an alignment error.

Those last two are the interesting pair, because the standard makes them mutually exclusive by construction. A frame with multiple error conditions is counted exclusively — by the single status the MAC service reported to its client, and no other. So a frame that is both misaligned and fails its check is an alignment error and is not counted as an FCS error, even though its check did fail.

Integral octetsCheck sequenceCounted as
ayespassesvalid
byesfailsFCS error
cnofailsalignment error
dno"passes"cannot occur — see below

Row d is worth a moment. A frame that is not a whole number of octets has bits the check was never computed over, so a "pass" is not meaningful — and in practice the extra bits change the computation and it fails. The standard does not define a class for it because the class is empty.

Which gives a receive path a strong structural requirement: its classifier must produce exactly one class per frame. Not a set of flags to be interpreted downstream — Chapter 7.2 §9's accounting already assumed this, and here is where the assumption is normative rather than convenient.

4. RTL 1 — One Class Per Frame

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Produces exactly ONE validity class per frame.
//
// The priority order is not arbitrary and is not a design preference: it
// follows the standard's rule that a frame with several error conditions
// is counted exclusively, by the single status reported upward. Getting
// the order wrong produces counters that are individually plausible and
// collectively wrong.
//
// Order, and why each is where it is:
//
//   1. TRUNCATED     -- carrier lost. There is no complete frame to
//                       classify, so nothing below can be evaluated.
//   2. ALIGNMENT     -- not a whole number of octets. Takes precedence
//                       over FCS by the standard's own definition.
//   3. FCS           -- whole octets, check failed.
//   4. UNDERSIZE     -- below the floor, check PASSED (Chapter 5.6 §8:
//                       a good check means the peer emitted it that way).
//   5. OVERSIZE      -- above the applicable STANDARD maximum.
//   6. VALID
//
// Note what is NOT in this list: anything about a local ceiling. That is
// a different predicate and Section 6 keeps it separate.
package validity_pkg;
 
  typedef enum logic [3:0] {
    V_VALID,
    V_TRUNCATED,     // carrier lost mid-frame
    V_ALIGNMENT,     // not an integral number of octets, check failed
    V_FCS,           // integral octets, check failed
    V_UNDERSIZE,     // below 64 octets, check PASSED
    V_FRAGMENT,      // below 64 octets, check FAILED
    V_OVERSIZE       // above the standard maximum, check passed
  } validity_e;
 
  // NORMATIVE. Chapter 5.6's floor and Chapter 5.7's three maxima.
  localparam int unsigned MIN_FRAME    = 64;
  localparam int unsigned MAX_BASIC    = 1518;
  localparam int unsigned MAX_QTAGGED  = 1522;
  localparam int unsigned MAX_ENVELOPE = 2000;
 
endpackage
 
module frame_validity_classifier
  import validity_pkg::*;
(
  input  logic clk,
  input  logic rst_n,
 
  input  logic        frame_done,
  input  logic [13:0] frame_octets,
  // Bits beyond the last complete octet, 0 to 7. Section 8 produces it.
  input  logic [2:0]  dribble_bits,
  input  logic        fcs_ok,
  input  logic        truncated,
  input  logic [1:0]  tags_present,
 
  output logic        class_valid,
  output validity_e   frame_class,
  // The maximum this frame was judged against, so a reader can see WHICH
  // normative ceiling applied rather than inferring it.
  output logic [13:0] applicable_max
);
 
  // Chapter 5.7 §3: the applicable maximum depends on the frame's own
  // structure, not on configuration. An envelope frame is judged against
  // 2000 whether or not this device would accept one.
  wire [13:0] normative_max = (tags_present == 2'd0) ? 14'(MAX_BASIC)
                            : (tags_present == 2'd1) ? 14'(MAX_QTAGGED)
                                                     : 14'(MAX_ENVELOPE);
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      class_valid    <= 1'b0;
      frame_class    <= V_VALID;
      applicable_max <= 14'(MAX_BASIC);
    end else begin
      class_valid <= frame_done;
 
      if (frame_done) begin
        applicable_max <= normative_max;
 
        // The priority chain of the header comment, in order. Each arm is
        // reached only when every arm above it did not apply, which is
        // what "counted exclusively" means in RTL.
        if (truncated) begin
          frame_class <= V_TRUNCATED;
        end else if (dribble_bits != 3'd0) begin
          // Not a whole number of octets. Takes precedence over the check
          // result even though the check also failed -- Section 3's
          // row c, and the ordering the standard requires.
          frame_class <= V_ALIGNMENT;
        end else if (frame_octets < 14'(MIN_FRAME)) begin
          // Chapter 5.6 §8's split, and the check sequence is the only
          // thing that separates a damaged frame from a peer that emitted
          // a short one deliberately.
          frame_class <= fcs_ok ? V_UNDERSIZE : V_FRAGMENT;
        end else if (!fcs_ok) begin
          frame_class <= V_FCS;
        end else if (frame_octets > normative_max) begin
          frame_class <= V_OVERSIZE;
        end else begin
          frame_class <= V_VALID;
        end
      end
    end
  end
 
endmodule

Classification: synthesizable.

What it teaches: that the priority order is normative and the obvious order is wrong. The instinct is to check size first — it is the cheapest test — which classifies a misaligned 40-octet frame as a fragment and never reaches the alignment arm. The standard's exclusivity rule means the reported status determines the count, so an order that reports the wrong status produces counters that are each individually defensible and collectively non-conformant.

Deliberately simplified: tags_present arrives as an input. Counting tags is Chapter 5.5 §8's locator, and the point here is only that the applicable maximum is a property of the frame's structure rather than of this device.

Production implication: applicable_max is an output rather than an internal wire, and it earns its ports on the first oversize investigation. A frame reported oversize against 1518 when it carried a tag was judged by the wrong ceiling, and there is no way to see that from a boolean. Exposing which limit applied turns "this frame was too long" into "this frame was judged against 1518 and it is a tagged frame", which is a different and immediately actionable statement.

5. RTL 2 — Keeping the Local Predicate Out of the Normative One

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Splits "this frame was rejected" into the two predicates of Section 2
// and refuses to let them be summed.
//
//   NORMATIVE  -- from the classifier. A property of the frame. Every
//        conforming device agrees, and a non-VALID class means somebody
//        emitted or damaged a frame.
//
//   LOCAL      -- this device's ceiling, and whatever else configuration
//        imposes. A property of THIS DEVICE. A frame rejected only here
//        is conformant, and the finding is usually a parameter.
//
// The two outputs are deliberately not combinable into a single "reject"
// signal by this module. A datapath that needs one must form it itself,
// visibly, at a place a reviewer will see.
module validity_predicate_split
  import validity_pkg::*;
(
  input  logic clk,
  input  logic rst_n,
  input  logic clear,
 
  input  logic      class_valid,
  input  validity_e frame_class,
  input  logic [13:0] frame_octets,
  input  logic [13:0] applicable_max,
 
  // Configuration. NOT normative, and named so that nothing downstream
  // can mistake it for a standard limit.
  input  logic [13:0] local_ceiling,
  input  logic [13:0] local_floor,
 
  output logic malformed,             // the frame is at fault
  output logic unacceptable_here,     // this device declined a valid frame
  output logic acceptable,
 
  output logic [31:0] c_malformed,
  output logic [31:0] c_unacceptable_here,
  output logic [31:0] c_acceptable,
 
  // The number that ends most oversize investigations: the smallest
  // frame this device declined that the STANDARD would have allowed.
  // Compare it against local_ceiling and the fix is immediate.
  output logic [13:0] smallest_locally_declined,
  output logic        locally_declined_seen
);
 
  // A frame is malformed if and only if the normative classifier says so.
  // Configuration does not appear in this expression at all, and that is
  // the module's entire point.
  wire is_malformed = class_valid && (frame_class != V_VALID);
 
  // A frame that the standard accepts and this device does not. Note the
  // guard: it can only be true when the frame is NOT malformed, so the
  // two are exclusive by construction rather than by convention.
  wire is_local_only = class_valid && (frame_class == V_VALID) &&
                       ((frame_octets > local_ceiling) ||
                        (frame_octets < local_floor));
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      malformed <= 1'b0; unacceptable_here <= 1'b0; acceptable <= 1'b0;
      c_malformed <= '0; c_unacceptable_here <= '0; c_acceptable <= '0;
      smallest_locally_declined <= '1;
      locally_declined_seen <= 1'b0;
    end else begin
      malformed         <= 1'b0;
      unacceptable_here <= 1'b0;
      acceptable        <= 1'b0;
 
      if (clear) begin
        c_malformed <= '0; c_unacceptable_here <= '0; c_acceptable <= '0;
        // The smallest locally declined size deliberately survives: it is
        // a bound on where the ceiling would have to move, and a routine
        // clear must not erase it.
      end else if (class_valid) begin
        if (is_malformed) begin
          malformed   <= 1'b1;
          c_malformed <= c_malformed + 1'b1;
        end else if (is_local_only) begin
          unacceptable_here   <= 1'b1;
          c_unacceptable_here <= c_unacceptable_here + 1'b1;
          if (!locally_declined_seen || (frame_octets < smallest_locally_declined)) begin
            smallest_locally_declined <= frame_octets;
            locally_declined_seen     <= 1'b1;
          end
        end else begin
          acceptable   <= 1'b1;
          c_acceptable <= c_acceptable + 1'b1;
        end
      end
    end
  end
 
  // The relationship a design must never violate: a local ceiling above
  // the standard maximum is legitimate (jumbo), a local ceiling BELOW the
  // standard minimum is not -- it would reject conforming frames of every
  // size and is always a configuration error.
  // synopsys translate_off
  a_local_floor_sane: assert final (local_floor <= 14'(MIN_FRAME))
    else $fatal(1, "local floor above the standard minimum rejects conforming frames");
  // synopsys translate_on
 
endmodule

Classification: synthesizable.

What it teaches: that the two predicates must be exclusive by construction rather than by convention. is_local_only is guarded on frame_class == V_VALID, so a malformed frame can never also be counted as locally declined — which matters because a 40-octet fragment is both below the floor and below any local floor, and a design without the guard counts it twice and attributes it to the wrong owner half the time.

Deliberately simplified: the local predicate is a size window. Real configuration is richer — a device may decline frames by VLAN, by port state, or by policy — and each addition belongs on this side of the split, not the other.

Production implication: smallest_locally_declined is the number that ends most oversize investigations, and Chapter 5.7 §7 built the same idea for a different question. A device with local_ceiling at 1518 and smallest_locally_declined at 1522 has a tag it did not budget for; the same device with 9018 has a neighbour running jumbo. One register read replaces a conversation with whoever operates the peer.

6. Alignment Errors and Dribble Bits

A received frame ends part way through an octet. The complete octets are passed to the check, and the leftover bits beyond the last complete octet are called dribble bits. Because the frame is not an integral number of octets, the standard classifies it as an alignment error rather than as a check sequence error, even though the check also fails. The leftover bits must be counted rather than discarded, because their presence is what selects the classification.Complete octetswhat the check sawDribble bits1 to 7 leftover bitsAlignment errornot an FCS errorCounted exclusivelyone status, not twoCount, do notdiscardtheir presence selects theclassZero at 1G and abovethe encoding cannot carrythem12
Figure 2 — a frame that ends part-way through an octet, and why the leftover bits change the classification rather than being discarded.

A frame that ends part-way through an octet leaves one to seven bits that belong to no octet. They are usually called dribble bits, and the instinct — discard them, they are not data — throws away the only evidence that selects the classification.

Their presence is the classification. Section 3's table: whole octets plus a failed check is an FCS error; not whole octets plus a failed check is an alignment error. The distinction is entirely in whether any dribble bits arrived.

Which means a receive path must count them before deciding anything, and must count them even though it will never use their values.

And the physical cause is worth knowing because it points at a specific place. Dribble bits arise when the receiver's bit clock and the frame's actual end disagree — a marginal channel where the last transitions are recovered late, a squelch threshold crossed at the wrong moment, or a duplex mismatch where a collision truncated the frame at a bit boundary rather than an octet one. All of them are physical-layer or link-configuration stories, never frame-format ones.

Then the modern caveat from Section 3's callout. At 1 Gb/s and above, Chapter 3.5's encodings carry many bits per code group, so a partial octet cannot reach the MAC as a partial octet. The counter should still exist and should read zero — and a non-zero value is evidence of a fault inside this device, between the decoder and the MAC, rather than on the link.

7. RTL 3 — Detecting a Frame That Is Not Whole Octets

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Counts bits after the last complete octet and reports how many.
//
// The count is what matters, not the values. Section 6: the PRESENCE of
// dribble bits is what selects alignment error over FCS error, so a
// receive path that discards them has discarded its own classification
// evidence.
//
// The module also reports the count rather than a flag, because the
// number is diagnostic: a consistent 4 bits points at a nibble-wide
// width adapter losing a transfer; a varying 1 to 7 points at the
// physical layer.
module alignment_error_detector
  import validity_pkg::*;
#(
  parameter int unsigned CNT_W = 32
) (
  input  logic clk,
  input  logic rst_n,
  input  logic clear,
 
  input  logic frame_start,
  // One bit per clock from the decoder, with an octet boundary marker.
  input  logic bit_valid,
  input  logic octet_complete,
  input  logic carrier,
 
  output logic       frame_done,
  output logic [2:0] dribble_bits,
  output logic       misaligned,
 
  output logic [CNT_W-1:0] c_misaligned,
  // Distribution of dribble counts. A histogram over seven buckets,
  // because WHICH count recurs names the cause.
  output logic [CNT_W-1:0] dribble_hist [7],
 
  // Sticky. At 1 Gb/s and above this must never fire (Section 6), so a
  // single occurrence is a finding about this device rather than a rate
  // to be trended.
  output logic misaligned_seen
);
 
  logic [2:0] partial_q;
  logic       in_frame_q;
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      partial_q    <= '0;
      in_frame_q   <= 1'b0;
      frame_done   <= 1'b0;
      dribble_bits <= '0;
      misaligned   <= 1'b0;
      c_misaligned <= '0;
      for (int i = 0; i < 7; i++) dribble_hist[i] <= '0;
      misaligned_seen <= 1'b0;
    end else begin
      frame_done <= 1'b0;
      misaligned <= 1'b0;
 
      if (clear) begin
        c_misaligned <= '0;
        for (int i = 0; i < 7; i++) dribble_hist[i] <= '0;
        // misaligned_seen deliberately survives.
      end
 
      if (frame_start) begin
        partial_q  <= '0;
        in_frame_q <= 1'b1;
      end else if (in_frame_q) begin
        if (octet_complete) begin
          // A complete octet resets the partial count. Everything the
          // check sequence consumed is here.
          partial_q <= '0;
        end else if (bit_valid) begin
          partial_q <= partial_q + 1'b1;
        end
 
        if (!carrier) begin
          // The frame ended. Whatever is in partial_q is the dribble.
          in_frame_q   <= 1'b0;
          frame_done   <= 1'b1;
          dribble_bits <= partial_q;
          if (partial_q != 3'd0) begin
            misaligned      <= 1'b1;
            misaligned_seen <= 1'b1;
            c_misaligned    <= c_misaligned + 1'b1;
            dribble_hist[partial_q - 3'd1] <= dribble_hist[partial_q - 3'd1] + 1'b1;
          end
        end
      end
    end
  end
 
endmodule

Classification: synthesizable.

What it teaches: that the dribble count is diagnostic and a flag is not. A histogram concentrated at 4 points at a nibble-wide width adapter — Chapter 4.5's xMII family includes 4-bit interfaces — losing or gaining a transfer inside this device. A spread across 1 to 7 points at the physical layer, where the last transitions are being recovered at a bit boundary that varies with the channel. Two different buildings, distinguished by the shape of a seven-bucket histogram.

Deliberately simplified: bit-serial with an explicit octet marker. A parallel receive path gets the same information from a byte-enable that is partially set on the last transfer, which is Chapter 6.4 §6's problem seen from the receive side.

Production implication: misaligned_seen is sticky and survives clear because at 1 Gb/s and above the count must be zero. Section 6 explained why: the encodings carry many bits per code group, so a partial octet cannot cross the decoder. A single occurrence on a gigabit link is therefore not a rate to trend but a fault inside this device — and treating it as a statistic to be cleared loses the one event worth investigating.

8. RTL 4 — What to Do With the Leftover Bits

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Handles the dribble bits themselves: they must not enter the check
// computation, must not be delivered to the client, and must not be
// silently dropped without being counted.
//
// Three wrong behaviours, all of which produce a plausible result:
//
//   1. feed them to the CRC engine -- the check now covers a fractional
//      octet, and Chapter 5.8's covered range is violated in a way no
//      peer can see because the frame was going to fail anyway
//   2. round them up into a padded final octet -- the frame becomes a
//      whole number of octets and is misclassified as an FCS error
//   3. discard them without counting -- the frame is misclassified in
//      the other direction, as an FCS error, because the evidence is gone
//
// All three convert an alignment error into an FCS error, which sends the
// investigation from the physical layer to the wrong place.
module dribble_bit_handler
  import validity_pkg::*;
(
  input  logic clk,
  input  logic rst_n,
 
  input  logic       bit_valid,
  input  logic       bit_in,
  input  logic       octet_complete,
  input  logic       carrier,
  input  logic       frame_start,
 
  // To the check engine. Gated so that a partial octet never enters.
  output logic       crc_bit_valid,
  output logic       crc_bit,
 
  // To the client. Likewise.
  output logic       cli_octet_valid,
  output logic [7:0] cli_octet,
 
  // To the classifier of Section 4.
  output logic [2:0] dribble_out,
  output logic       dribble_valid
);
 
  logic [7:0] sh_q;
  logic [2:0] cnt_q;
  logic       in_frame_q;
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      sh_q <= '0; cnt_q <= '0; in_frame_q <= 1'b0;
      crc_bit_valid <= 1'b0; crc_bit <= 1'b0;
      cli_octet_valid <= 1'b0; cli_octet <= '0;
      dribble_out <= '0; dribble_valid <= 1'b0;
    end else begin
      crc_bit_valid   <= 1'b0;
      cli_octet_valid <= 1'b0;
      dribble_valid   <= 1'b0;
 
      if (frame_start) begin
        cnt_q      <= '0;
        in_frame_q <= 1'b1;
      end else if (in_frame_q) begin
        if (bit_valid) begin
          sh_q <= {sh_q[6:0], bit_in};
          // Bits enter the CRC one at a time as they arrive -- but only
          // as part of a complete octet, which the gate below enforces.
          if (cnt_q == 3'd7) begin
            cnt_q           <= '0;
            cli_octet_valid <= 1'b1;
            cli_octet       <= {sh_q[6:0], bit_in};
          end else begin
            cnt_q <= cnt_q + 1'b1;
          end
        end
 
        if (!carrier) begin
          in_frame_q    <= 1'b0;
          // Report the leftover count. The BITS themselves go nowhere:
          // not to the check (failure 1), not padded into an octet
          // (failure 2), and not dropped unrecorded (failure 3).
          dribble_out   <= cnt_q;
          dribble_valid <= 1'b1;
          cnt_q         <= '0;
        end
      end
    end
  end
 
  // The gate that keeps a partial octet out of the check. It is written
  // as a separate always_comb rather than folded above so that it is
  // visible: this is Chapter 5.8's covered range, enforced at the one
  // place a fractional octet could sneak into it.
  always_comb begin
    crc_bit_valid = bit_valid && in_frame_q && carrier;
    crc_bit       = bit_in;
  end
 
endmodule

Classification: synthesizable.

What it teaches: that all three wrong behaviours converge on the same misclassification. Feeding the dribble bits to the check, padding them into an octet, or discarding them unrecorded — each produces a frame that looks like a whole number of octets to the classifier, so each turns an alignment error into an FCS error. Three different bugs, one indistinguishable symptom, and the symptom points at the link when the cause may be a width adapter inside this device.

Deliberately simplified: the CRC gate is written as a separate combinational block that could have been folded into the sequential logic. Keeping it visible is the point — it is Chapter 5.8's covered range at the one place a fractional octet could enter it, and a reviewer should be able to find it without reading the shift register.

Production implication: cli_octet_valid fires only on complete octets, so a client never sees a partial one. That sounds obvious and the failure is not: a design that delivers the shift register's contents at carrier loss hands the client an octet made of leftover bits and zeros, which is plausible data with no marking. The frame will be discarded by the classifier anyway — but on a cut-through path (Chapter 7.2 §4) those octets have already been released, so the abort has to arrive before the client acts on them.

9. Count and Forward — When Dropping Is Wrong

An intermediate device applies a local check to a frame passing through it. If the check is normative, such as a failed frame check sequence, dropping is correct because the frame is malformed and no downstream device could use it. If the check is local, such as this device's own ceiling being lower than the path's, dropping silently removes a conformant frame and produces the black hole behaviour described earlier. In that case counting and forwarding preserves the path while making the mismatch visible.Frame arrivesat an intermediate deviceNormative failuremalformed by the standardDrop and countcorrect — nobody can useitLocal failure onlyconformant, declined hereCount and forwardwhere the limit is notthis device'sDrop silentlythe black hole of Chapter5.712
Figure 3 — a device in the middle of a path may be the wrong place to enforce a limit that belongs to the endpoints.

Dropping is not always the right action, and the cases divide exactly along Section 2's line.

A malformed frame should be dropped. It is malformed everywhere, no downstream device can use it, and forwarding it wastes capacity and propagates a fault. The only exception is a cut-through device that has already forwarded most of it — which cannot drop and marks instead, Chapter 5.8 §9's stomp.

A frame that fails only a local check is a different matter, and the right action depends on what the device is for.

At an endpoint, dropping is correct. The frame is being delivered here, this device cannot handle it, and there is nowhere else for it to go.

At an intermediate device, dropping may be exactly wrong. The frame is passing through, its destination may handle it perfectly well, and the limit being enforced belongs to a device that is not a party to the conversation. Silently dropping it produces Chapter 5.7 §11's black hole — small frames pass, large ones vanish, no errors anywhere.

So the third option is to count and forward: honour the frame, record that it exceeded a local expectation, and let the endpoints discover the mismatch through their own mechanisms rather than having this device silently enforce a limit nobody asked it to.

That is not always available. A device that genuinely cannot buffer a 9018-octet frame cannot forward one, and the limit is then physical rather than configured — which is why Chapter 5.7 §5's build-time assertion compares the configured ceiling against the buffer. When the ceiling is a configuration and the buffer would cope, counting and forwarding is the option that does not create a black hole.

10. RTL 5 — Checking the Classification Against Itself

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE MONITOR.
//
// Verifies the classifier's own invariants, which are unusual in being
// almost entirely about EXCLUSIVITY rather than about values.
//
// Section 3 established that the standard counts a frame by exactly one
// status. A classifier that satisfies that produces counters whose sum
// equals the frame count -- and one that does not produces counters that
// each look right and sum to more than the traffic.
//
// The sum check is the whole monitor, and it is the check nothing else
// performs: every individual counter can be verified against its own
// stimulus, and only the total reveals a frame counted twice.
module validity_conformance_monitor
  import validity_pkg::*;
#(
  parameter int unsigned CNT_W = 32
) (
  input  logic clk,
  input  logic rst_n,
  input  logic clear,
 
  input  logic      class_valid,
  input  validity_e frame_class,
  input  logic      malformed,
  input  logic      unacceptable_here,
  input  logic      acceptable,
 
  input  logic [13:0] frame_octets,
  input  logic [13:0] applicable_max,
  input  logic [2:0]  dribble_bits,
  input  logic        fcs_ok,
 
  output logic [CNT_W-1:0] c_frames,
  output logic [CNT_W-1:0] c_by_class [7],
 
  // Exclusivity violations, which are the only failures this can see.
  output logic             double_counted,
  output logic             unclassified,
  output logic [CNT_W-1:0] c_exclusivity_error,
 
  // Ordering violations: a class that contradicts its own evidence.
  output logic             ordering_error,
  output logic [CNT_W-1:0] c_ordering_error,
 
  output logic             any_violation      // sticky
);
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      c_frames <= '0;
      for (int i = 0; i < 7; i++) c_by_class[i] <= '0;
      double_counted <= 1'b0; unclassified <= 1'b0;
      c_exclusivity_error <= '0;
      ordering_error <= 1'b0; c_ordering_error <= '0;
      any_violation <= 1'b0;
    end else begin
      double_counted <= 1'b0;
      unclassified   <= 1'b0;
      ordering_error <= 1'b0;
 
      if (clear) begin
        c_frames <= '0;
        for (int i = 0; i < 7; i++) c_by_class[i] <= '0;
        c_exclusivity_error <= '0; c_ordering_error <= '0;
        // any_violation deliberately survives.
      end else if (class_valid) begin
        c_frames <= c_frames + 1'b1;
        c_by_class[frame_class] <= c_by_class[frame_class] + 1'b1;
 
        // Exactly one of the three predicate outputs. Section 5 made them
        // exclusive by construction; this checks the construction held.
        if (!$onehot({malformed, unacceptable_here, acceptable})) begin
          if (malformed + unacceptable_here + acceptable > 1) double_counted <= 1'b1;
          else                                                unclassified   <= 1'b1;
          c_exclusivity_error <= c_exclusivity_error + 1'b1;
          any_violation       <= 1'b1;
        end
 
        // The class must be consistent with the evidence that produced
        // it. Each of these is a case the priority chain of Section 4
        // could get wrong while still emitting exactly one class.
        if (((frame_class == V_ALIGNMENT) && (dribble_bits == 3'd0)) ||
            ((frame_class == V_FCS)       && (dribble_bits != 3'd0)) ||
            ((frame_class == V_FCS)       && fcs_ok)                 ||
            ((frame_class == V_UNDERSIZE) && !fcs_ok)                ||
            ((frame_class == V_FRAGMENT)  && fcs_ok)                 ||
            ((frame_class == V_OVERSIZE)  && (frame_octets <= applicable_max))) begin
          ordering_error   <= 1'b1;
          c_ordering_error <= c_ordering_error + 1'b1;
          any_violation    <= 1'b1;
        end
      end
    end
  end
 
endmodule

Classification: synthesizable monitor.

What it teaches: that the consistency check is between a class and the evidence that should have produced it, which is a different question from whether the class is right. A classifier can emit exactly one class per frame — satisfying exclusivity — and emit V_FCS on a frame with dribble bits, which is a priority-order error rather than an exclusivity one. The two failures need separate checks because they have separate causes: exclusivity breaks when a design uses flags, ordering breaks when a design puts the cheap test first.

Deliberately simplified: the ordering checks enumerate the contradictions rather than deriving them. Deriving them would mean reimplementing the classifier, which is Chapter 6.4 §11's rejected property — a checker sharing the design's logic proves nothing.

Production implication: the sum of c_by_class must equal c_frames, and that is the only check in the design that sees a frame counted twice. Every individual counter can be verified against its own directed stimulus and still be wrong in aggregate — a frame that increments both the fragment and the alignment counters passes both of those tests. It is the same conservation argument Chapter 7.2 §10 made for frames that vanish, applied to frames that duplicate.

11. Assertions — Exclusivity, Ordering and the Line Between Two Predicates

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// P1 -- THE NORMATIVE RULE. Exactly one class per frame. Section 3
// showed this is required by the standard's counting convention, not
// merely convenient.
// ---------------------------------------------------------------------
property p_exactly_one_class;
  @(posedge clk) disable iff (!rst_n)
    class_valid |-> (frame_class inside {V_VALID, V_TRUNCATED, V_ALIGNMENT,
                                         V_FCS, V_UNDERSIZE, V_FRAGMENT, V_OVERSIZE});
endproperty
a_exactly_one_class: assert property (p_exactly_one_class);
 
// ---------------------------------------------------------------------
// P2 -- Alignment takes precedence over FCS. A misaligned frame is
// counted as an alignment error even though its check also failed.
// ---------------------------------------------------------------------
property p_alignment_precedes_fcs;
  @(posedge clk) disable iff (!rst_n)
    (class_valid && ($past(dribble_bits) != 3'd0) && !$past(truncated))
      |-> (frame_class == V_ALIGNMENT);
endproperty
a_alignment_precedes_fcs: assert property (p_alignment_precedes_fcs)
  else $error("a misaligned frame was counted as an FCS error");
 
// ---------------------------------------------------------------------
// P3 -- An FCS error is a whole number of octets, by definition.
// ---------------------------------------------------------------------
property p_fcs_error_is_whole_octets;
  @(posedge clk) disable iff (!rst_n)
    (class_valid && (frame_class == V_FCS)) |-> ($past(dribble_bits) == 3'd0);
endproperty
a_fcs_error_is_whole_octets: assert property (p_fcs_error_is_whole_octets);
 
// ---------------------------------------------------------------------
// P4 -- Truncation outranks everything. There is no complete frame to
// classify, so nothing below it can be evaluated.
// ---------------------------------------------------------------------
property p_truncation_outranks;
  @(posedge clk) disable iff (!rst_n)
    (class_valid && $past(truncated)) |-> (frame_class == V_TRUNCATED);
endproperty
a_truncation_outranks: assert property (p_truncation_outranks);
 
// ---------------------------------------------------------------------
// P5 -- Chapter 5.6 §8's split, restated where it is classified: below
// the floor, the check sequence alone separates the two classes.
// ---------------------------------------------------------------------
property p_short_frame_split_by_fcs;
  @(posedge clk) disable iff (!rst_n)
    (class_valid && ($past(frame_octets) < 14'(MIN_FRAME)) &&
     ($past(dribble_bits) == 3'd0) && !$past(truncated))
      |-> (frame_class == ($past(fcs_ok) ? V_UNDERSIZE : V_FRAGMENT));
endproperty
a_short_frame_split_by_fcs: assert property (p_short_frame_split_by_fcs);
 
// ---------------------------------------------------------------------
// P6 -- The applicable maximum is a property of the FRAME's structure,
// never of this device's configuration.
// ---------------------------------------------------------------------
property p_applicable_max_is_normative;
  @(posedge clk) disable iff (!rst_n)
    class_valid |-> (applicable_max inside {14'(MAX_BASIC), 14'(MAX_QTAGGED),
                                            14'(MAX_ENVELOPE)});
endproperty
a_applicable_max_is_normative: assert property (p_applicable_max_is_normative);
 
// ---------------------------------------------------------------------
// P7 -- THE SEPARATION. A frame the standard accepts is never counted as
// malformed, whatever this device is configured for.
// ---------------------------------------------------------------------
property p_conformant_never_malformed;
  @(posedge clk) disable iff (!rst_n)
    (class_valid && (frame_class == V_VALID)) |-> !malformed;
endproperty
a_conformant_never_malformed: assert property (p_conformant_never_malformed)
  else $error("a conformant frame was counted as malformed");
 
// ---------------------------------------------------------------------
// P8 -- And the converse: a locally declined frame is one the standard
// accepted. The two predicates are exclusive by construction (Section 5).
// ---------------------------------------------------------------------
property p_local_decline_implies_conformant;
  @(posedge clk) disable iff (!rst_n)
    unacceptable_here |-> (frame_class == V_VALID);
endproperty
a_local_decline_implies_conformant: assert property (p_local_decline_implies_conformant);
 
// ---------------------------------------------------------------------
// P9 -- Exactly one of the three predicate outputs, every frame.
// ---------------------------------------------------------------------
property p_predicates_onehot;
  @(posedge clk) disable iff (!rst_n)
    class_valid |-> $onehot({malformed, unacceptable_here, acceptable});
endproperty
a_predicates_onehot: assert property (p_predicates_onehot);
 
// ---------------------------------------------------------------------
// P10 -- CONSERVATION. The per-class counters sum to the frame count.
// The only check that sees a frame counted twice.
// ---------------------------------------------------------------------
property p_class_counters_conserve;
  @(posedge clk) disable iff (!rst_n)
    class_valid |=> (class_sum == c_frames);
endproperty
a_class_counters_conserve: assert property (p_class_counters_conserve);
 
// ---------------------------------------------------------------------
// P11 -- The local floor never rises above the standard minimum. A
// configuration that does rejects conforming frames of every size.
// ---------------------------------------------------------------------
property p_local_floor_sane;
  @(posedge clk) disable iff (!rst_n)
    (local_floor <= 14'(MIN_FRAME));
endproperty
a_local_floor_sane: assert property (p_local_floor_sane);
 
// ---------------------------------------------------------------------
// P12 -- Dribble bits never enter the check computation. Chapter 5.8's
// covered range, at the one place a fractional octet could reach it.
// ---------------------------------------------------------------------
property p_dribble_never_in_crc;
  @(posedge clk) disable iff (!rst_n)
    (!carrier) |-> !crc_bit_valid;
endproperty
a_dribble_never_in_crc: assert property (p_dribble_never_in_crc);
 
// ---------------------------------------------------------------------
// P13 -- A partial octet is never delivered to the client.
// ---------------------------------------------------------------------
property p_no_partial_octet_delivered;
  @(posedge clk) disable iff (!rst_n)
    cli_octet_valid |-> ($past(cnt_q) == 3'd7);
endproperty
a_no_partial_octet_delivered: assert property (p_no_partial_octet_delivered);
 
// ---------------------------------------------------------------------
// P14 -- The dribble count is bounded. Eight leftover bits would be a
// complete octet and a counter that can reach eight has an off-by-one.
// ---------------------------------------------------------------------
property p_dribble_bounded;
  @(posedge clk) disable iff (!rst_n)
    dribble_valid |-> (dribble_out <= 3'd7);
endproperty
a_dribble_bounded: assert property (p_dribble_bounded);
 
// ---------------------------------------------------------------------
// P15 -- Misalignment is sticky. At 1 Gb/s and above it must never
// occur, so a single event is a finding rather than a rate.
// ---------------------------------------------------------------------
property p_misaligned_seen_sticky;
  @(posedge clk) disable iff (!rst_n)
    misaligned_seen |=> misaligned_seen;
endproperty
a_misaligned_seen_sticky: assert property (p_misaligned_seen_sticky);
 
// ---------------------------------------------------------------------
// P16 -- The smallest locally declined size survives a counter clear:
// it bounds where the ceiling would have to move.
// ---------------------------------------------------------------------
property p_smallest_declined_survives;
  @(posedge clk) disable iff (!rst_n)
    clear |=> $stable(smallest_locally_declined);
endproperty
a_smallest_declined_survives: assert property (p_smallest_declined_survives);
 
// ---------------------------------------------------------------------
// P17 -- COVERAGE. Each class reached, including the two that ordinary
// traffic never produces.
// ---------------------------------------------------------------------
c_class_alignment: cover property (@(posedge clk) disable iff (!rst_n) (frame_class == V_ALIGNMENT));
c_class_undersize: cover property (@(posedge clk) disable iff (!rst_n) (frame_class == V_UNDERSIZE));
c_class_fragment:  cover property (@(posedge clk) disable iff (!rst_n) (frame_class == V_FRAGMENT));
c_class_oversize:  cover property (@(posedge clk) disable iff (!rst_n) (frame_class == V_OVERSIZE));
 
// ---------------------------------------------------------------------
// P18 -- COVERAGE. A frame that is conformant and locally declined --
// the middle predicate, which no malformed frame can reach.
// ---------------------------------------------------------------------
c_locally_declined_only: cover property (
  @(posedge clk) disable iff (!rst_n) unacceptable_here
);

12. Verification — Twenty-Four Scenarios and a Frame Two Devices Disagree About

#ScenarioStimulusWhat must be observed
1Valid minimum frame64 octets, good checkV_VALID; acceptable (P9)
2Valid maximum basic frame1518 octets, good checkV_VALID; applicable_max = 1518
3Tagged frame at 1522one tag, good checkV_VALID; applicable_max = 1522 (P6)
4Tagged frame judged against 1518force tags_present to 0V_OVERSIZE — the wrong-ceiling misclassification
5Envelope frame at 2000two tags, good checkV_VALID; applicable_max = 2000
6One above the applicable maximum1519 untagged, good checkV_OVERSIZE
7Fragment40 octets, bad checkV_FRAGMENT (P5)
8Undersize40 octets, good checkV_UNDERSIZE — a peer fault, not a link fault (P5)
9FCS error512 octets, bad check, whole octetsV_FCS (P3)
10Alignment error512 octets, bad check, 3 dribble bitsV_ALIGNMENT, not V_FCS (P2)
11Misaligned and short40 octets plus 5 dribble bitsV_ALIGNMENT — outranks the size classes
12Truncatedcarrier lost mid-frameV_TRUNCATED; outranks everything (P4)
13Truncated and misalignedcarrier lost part-way through an octetV_TRUNCATED — the priority chain's top
14Dribble histogram, physicaldribble counts spread 1 to 7histogram spread — a physical-layer signature
15Dribble histogram, internaldribble count always 4histogram concentrated — a nibble-width fault
16Dribble bits out of the checkany misaligned framecrc_bit_valid low after carrier loss (P12)
17Partial octet not deliveredany misaligned framecli_octet_valid never fires on a partial (P13)
18Locally declined, conformant1518 octets, local_ceiling = 1500unacceptable_here; not malformed (P7, P8)
19Smallest locally declinedseveral sizes above the ceilingsmallest_locally_declined = the smallest of them
20Malformed and below the local floor40-octet fragment, floor 64malformed only — not double-counted (P9)
21Local floor above the minimumlocal_floor = 128the build-time assertion fires
22Conservation10 000 mixed framesclass counters sum to the frame count (P10)
23Double count injectedforce two class countersdouble_counted; c_exclusivity_error
24Ordering violation injectedemit V_FCS on a misaligned frameordering_error (Section 10)

13. Debugging — Whose Fault, From Which Counter

Symptom — a device reports giants and the neighbour reports nothing wrong.

Read malformed against unacceptable_here before contacting anybody. If the frames are conformant and merely above this device's ceiling, the neighbour is correct and the fix is heresmallest_locally_declined names the value the ceiling would have to reach. Chapter 5.7 §6 showed this is the common case in a jumbo deployment, and the investigation habitually crosses an organisational boundary before anybody reads a local parameter.

Symptom — alignment errors on a gigabit link.

Not a link fault. Section 6's caveat: at 1 Gb/s and above the encoding carries many bits per code group, so a partial octet cannot cross the decoder. A non-zero count is a fault inside this device, between the decoder and the MAC. Read the dribble histogram: concentrated at 4 points at a nibble-wide width adapter losing a transfer; a spread of 1 to 7 would point at the physical layer and should be impossible here.

Symptom — FCS errors on a 10 or 100 Mb/s link and no alignment errors ever.

Suspect the classifier before the link. If dribble bits are being discarded, padded into an octet, or fed to the check, every alignment error is reported as an FCS error — Section 8's three convergent failures — and the counter that would have pointed at the physical layer reads zero forever. Confirm by checking whether the alignment counter has ever incremented on a link where it plausibly should.

Symptom — runts, and cable replacement changes nothing.

Read the split. A fragment has a bad check and was damaged in transit; an undersize frame has a good check and was emitted that wayChapter 5.6 §8's distinction, and the second is a peer conformance fault that no physical remedy touches.

Symptom — the error counters sum to more than the frames received.

A frame is being counted in two classes. Section 10's conservation check is the only thing that sees it, and the usual cause is a classifier built from independent flags rather than a priority chain — each flag is individually correct and a misaligned short frame sets two of them.

Symptom — an intermediate device is dropping large frames and both endpoints are configured identically.

The device in the middle is enforcing a limit that is not its business. Section 9's case: if the frame is conformant and this device could forward it, dropping produces a black hole — small frames pass, large ones vanish, no errors at either endpoint. Check whether the device's ceiling is a configuration or a buffer limit; the first should be raised or the frame counted and forwarded, and only the second is a genuine inability.

Symptom — a frame reported oversize at 1518 that is visibly 1520 octets and carries a tag.

The applicable maximum was wrong, not the frame. applicable_max should read 1522 for a singly tagged frame; if it reads 1518, tags_present is not reaching the classifier — Chapter 5.5 §8's displacement problem arriving in a new place, where its symptom is a misclassification rather than a misparse.

14. Common Misconceptions

"A frame is either valid or invalid."

The wrong model: one predicate, evaluated once.

What it costs: a single error counter that rises with traffic volume (unwanted frames), with a local misconfiguration (unacceptable frames), and with a real fault (malformed frames) — and an operator reading it cannot tell which happened.

The corrected model: three predicates with three owners. Malformed is a property of the frame and every device agrees. Unacceptable is a property of this device's configuration and two devices may differ. Unwanted is not a fault at all. Only the first is about the frame.

"A giant is a frame that is too long."

The wrong model: the counter's name describes the frame.

What it costs: the frame is escalated to whoever operates the peer, who finds nothing wrong — because nothing is wrong there. In a jumbo deployment this is the common case, not an edge case.

The corrected model: a frame above the standard maximum is malformed; a frame above this device's ceiling is conformant and merely declined here. The counter names should say which, and smallest_locally_declined turns the second into a number that names the fix.

"An alignment error is a kind of FCS error."

The wrong model: both mean a bad check, so either counter will do.

What it costs: the classification that would have pointed at the physical layer is reported as a generic check failure, and the dribble-bit evidence is thrown away. Section 8 showed three different ways to lose it, all converging on the same wrong answer.

The corrected model: the standard defines them against each other — whole octets plus a failed check is an FCS error, not whole octets plus a failed check is an alignment error — and counts a frame exclusively, by the single status reported upward. A frame is one or the other, never both.

"Dribble bits are leftovers; discard them."

The wrong model: they are not data, so they do not matter.

What it costs: their presence is what selects the classification. Discarding them without counting makes the frame look like a whole number of octets and turns an alignment error into an FCS error — which is the same outcome as feeding them to the check, or padding them into an octet.

The corrected model: count them, keep them out of the check, never deliver them — and report the count, because a histogram concentrated at 4 points inside this device while a spread of 1 to 7 points at the link.

"A device should drop anything it cannot accept."

The wrong model: enforcement is always correct.

What it costs: an intermediate device silently removing conformant frames produces Chapter 5.7 §11's black hole — small frames pass, large ones vanish, and no endpoint sees an error.

The corrected model: a check should be enforced by the party whose limit it is. A malformed frame is everybody's and should be dropped. A frame that fails only a local check at an intermediate device may be perfectly usable at its destination, and where the device could forward it, counting and forwarding preserves the path while making the mismatch visible.

15. Interview Reasoning

"What makes an Ethernet frame invalid?"

The weak answer lists conditions. The answer that ends the topic separates them first: malformed by the standard, unacceptable to this device, or valid and unwanted — three predicates with three owners, and only the first is a property of the frame. Then the normative list: below 64 octets, above the applicable standard maximum, a failed check with whole octets, a failed check with a partial octet. The payoff is that two devices always agree about the first predicate and may disagree about the second, on the identical octets.

"What is the difference between an alignment error and an FCS error?"

They are defined against each other: an FCS error is an integral number of octets and fails the check; an alignment error is not an integral number of octets and fails the check. The strong addition is the counting rule — a frame with several error conditions is counted exclusively, by the single status reported upward — which is why a receive path's classifier must produce one class per frame rather than a set of flags. And the modern caveat: at 1 Gb/s and above the encoding cannot carry a partial octet, so a non-zero alignment count is a fault inside the device.

"Your switch reports giants. Where do you start?"

Not with the peer. First: are the frames above the standard maximum, or merely above this device's ceiling? In a jumbo deployment the second dominates, the frames are conformant, and the fix is a local parameter — smallest_locally_declined names the value it needs. Adding that the counter's name is what sends people to the wrong place, because "giant" describes the frame and the finding is about the device, shows the failure mode is understood rather than the definition.

"When is it wrong to drop a frame that fails a check?"

When the check is local and the device is in the middle of a path. A malformed frame should be dropped — nobody can use it. A conformant frame that merely exceeds an intermediate device's ceiling may be perfectly usable at its destination, and dropping it silently creates a black hole where small frames pass and large ones vanish with no error at either endpoint. The general rule is that a check should be enforced by the party whose limit it is, and where the device can forward, counting and forwarding keeps the path while making the mismatch visible.

16. Understanding Check

Because three different authorities answer three different questions about the same octets.

Malformed is answered by the standard. Send the frame to ten devices and all ten agree, because the predicate is evaluated against a definition that does not vary. The evidence is in the octets.

Unacceptable here is answered by this device's configuration. Chapter 5.7 established the ceiling as a parameter, so the same 9018-octet frame is fine on one device and declined by its neighbour — and the frame is conformant in both cases. The evidence is in a register, not in the frame.

Unwanted is answered by the address filter, and it is not a fault in any sense. On a flooded segment it is most arrivals, which is why Chapter 7.2 §9 kept it out of the fault total as a denominator.

The failure mode is one counter containing all three. It rises with traffic volume, with a local misconfiguration, and with a real fault — and nothing in the number says which.

17. What's Next

The claim this chapter defended: "invalid" is three predicates with three owners, and only one of them is a property of the frame.

Malformed is decided by the standard and every device agrees. Unacceptable is decided by this device's configuration, so two devices may disagree about the identical octets — and in a jumbo deployment that case dominates, which is why a counter named for the frame sends investigations to a peer that is behaving correctly. Unwanted is not a fault at all.

Within the normative predicate, the definitions are narrower than they look and two of them are defined against each other: whole octets plus a failed check is an FCS error, a partial octet plus a failed check is an alignment error, and the standard counts a frame exclusively by the one status reported upward. That makes a single-enum classifier with a priority chain a requirement rather than a style, and it makes the dribble-bit count evidence rather than debris. And where a failing check is local and the device is in the middle of a path, the right action may be to count and forward, because a check should be enforced by the party whose limit it is.

Chapter 7.4 — Address Filtering in Hardware takes the third predicate, the one this chapter deliberately left alone. Chapter 5.4 owns the one-sided hash and why its false positives are what make it affordable; 7.4 owns the engine — a perfect-match table for the station's own addresses, the hash for groups, promiscuous and all-multicast modes, and the priority order in which they compose.

And its argument is that the filter is not a predicate at all but a set of accept reasons, deliberately overlapping — so a design that cannot say which reason accepted a frame cannot explain why it is receiving traffic it did not expect.

The full path is on the Ethernet curriculum index.

Continue learning

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.