← CCNP Enterprise: ENCOR core and operations
15 / 20 · 55 MIN

QoS: bursts, queues and delay budgets

Calculate burst conformance and queue waiting while identifying each model’s limits.

Average rate and burst are different dimensions

The first model uses one initially full token bucket, continuous replenishment and whole-packet dropping when tokens are insufficient. Rate is 8,000,000 bits/s, equivalent to 1,000 bytes per millisecond, and the bucket holds 2,000 bytes. Four 1,000-byte packets arrive at time zero. The first two find credit; the other two are dropped. A fifth packet arrives at 10 ms and finds the bucket full again. Averaging these 5,000 bytes over a 10-ms window gives 4 Mb/s, below 8 Mb/s, but that average does not describe the initial burst pressure.

Case: a queue fixes drops but violates delay

The second model is an 8-Mb/s fixed-rate FIFO without burst credit. It does not reproduce a specific Cisco shaper. Each 1,000-byte packet takes 1 ms to serve. With 4,000-byte capacity, the first four packets enter and finish at 1, 2, 3 and 4 ms; the fourth waits 3 ms before service. With 2,000-byte capacity, the last two burst packets are dropped. Capacity includes the packet in service, and completions at time t free space before arrivals at that time. Results depend on these explicit assumptions.

Policing, shaping and finite capacity

Policing can drop or remark excess according to its configured action; our model implements dropping only. Shaping uses waiting and scheduling to control output, but queues are finite and can drop packets. Do not conclude that any shaping eliminates loss or that every policer behaves like one bucket. After a long idle period, model credit remains capped at 2,000 bytes. A 3,000-byte packet never fits that bucket even after waiting. In production, confirm implementation rate, burst, units, actions and overhead accounting before choosing a change.

Sustained excess does not fit a small budget

In a separate fluid model, 150 Mb/s arrives and 100 Mb/s leaves for 200 ms. Without loss or sender reaction, 1,250,000 bytes accumulate. If arrivals stop then, draining takes 100 ms at 100 Mb/s. Sustaining excess for 20 seconds would accumulate 125,000,000 bytes and require 10 seconds to drain. These calculations use decimal units and exclude overhead, TCP and finite capacity. Increasing a queue can absorb a brief burst but cannot create capacity for sustained load above service rate. For APS, relate delay limits to the batch window and concurrent transactions.

Reproduce and compare with the real network

Save the complete script below as simulate.py and run python3 simulate.py /tmp/qos-evidence.json. It uses only Python’s standard library and writes local results without network access. Two runs were checked with 19 assertions each. Change one variable at a time: bucket size, FIFO capacity, arrival spacing or excess duration. Before transferring a conclusion to a project, collect burst, drop, delay and classification measurements on the actual platform. The model contains no TCP, overhead, multiple queues, priority or vendor scheduler. A calculated value is neither a measured SLA nor an approved production configuration.

# Save as simulate.py; run: python3 simulate.py /tmp/qos-evidence.json
"""Original didactic models. No network/device access or Cisco scheduler emulation."""
from collections import deque
from fractions import Fraction
import datetime,hashlib,json,pathlib,sys

def inputs(arrivals,rate_bps,capacity):
 if rate_bps<=0 or capacity<=0:raise ValueError('Positive rate and capacity required')
 previous=Fraction(0)
 for ms,size in arrivals:
 if ms<previous or ms<0 or size<=0:raise ValueError('Ordered nonnegative times and positive sizes required')
 previous=Fraction(ms)

def police(arrivals,rate_bps,bucket_bytes):
 """One bucket, initially full, continuous refill, whole-packet exceed drop."""
 inputs(arrivals,rate_bps,bucket_bytes);rate=Fraction(rate_bps,8000)
 tokens=Fraction(bucket_bytes);last=Fraction(0);rows=[]
 for index,(ms,size) in enumerate(arrivals):
 at=Fraction(ms);tokens=min(Fraction(bucket_bytes),tokens+(at-last)*rate);before=tokens
 admitted=tokens>=size
 if admitted:tokens-=size
 rows.append({'packet':index+1,'arrivalMs':float(at),'bytes':size,'tokensBefore':float(before),'admitted':admitted,'tokensAfter':float(tokens)})
 last=at
 return rows

def fifo(arrivals,rate_bps,capacity_bytes):
 """Fixed-rate FIFO serializer; capacity includes the packet in service.
 Completions at time t free capacity before arrivals at t. No token credit.
 """
 inputs(arrivals,rate_bps,capacity_bytes);pending=deque;last_finish=Fraction(0);rows=[]
 for index,(ms,size) in enumerate(arrivals):
 at=Fraction(ms)
 while pending and pending[0][0]<=at:pending.popleft
 used=sum(s for _,s in pending);admitted=used+size<=capacity_bytes
 row={'packet':index+1,'arrivalMs':float(at),'bytes':size,'occupiedBytesBefore':used,'admitted':admitted}
 if admitted:
 start=max(at,last_finish);finish=start+Fraction(size*8000,rate_bps)
 pending.append((finish,size));last_finish=finish
 row.update(startMs=float(start),finishMs=float(finish),waitMs=float(start-at),totalMs=float(finish-at))
 rows.append(row)
 return rows

def match(criteria,mode):
 if not criteria or mode not in ['any','all']:raise ValueError('Nonempty criteria and any/all mode required')
 return any(criteria) if mode=='any' else all(criteria)

def backlog(arrival_bps,service_bps,duration_ms):
 if arrival_bps<0 or service_bps<=0 or duration_ms<0:raise ValueError('Invalid rate or duration')
 queued=max(Fraction(0),Fraction((arrival_bps-service_bps)*duration_ms,8000))
 return {'queuedBytes':float(queued),'drainMsIfArrivalsStop':float(queued*8000/service_bps)}

def run:
 checks=[]
 def verify(name,condition):
 if not condition:raise AssertionError(name)
 checks.append(name)
 arrivals=[(0,1000),(0,1000),(0,1000),(0,1000),(10,1000)]
 policed=police(arrivals,8_000_000,2000);wide=fifo(arrivals,8_000_000,4000);small=fifo(arrivals,8_000_000,2000)
 verify('full bucket admits first two burst packets',[x['admitted']for x in policed]==[True,True,False,False,True])
 verify('dropped packets do not consume unavailable tokens',policed[2]['tokensAfter']==policed[3]['tokensAfter']==0)
 verify('idle refill is capped at bucket size',policed[4]['tokensBefore']==2000)
 verify('four-kilobyte FIFO admits entire input',all(x['admitted']for x in wide))
 verify('FIFO exposes increasing burst wait',[x['waitMs']for x in wide]==[0,1,2,3,0])
 verify('FIFO completion includes one millisecond serialization',[x['finishMs']for x in wide]==[1,2,3,4,11])
 verify('two-kilobyte FIFO drops excess burst packets',[x['admitted']for x in small]==[True,True,False,False,True])
 oversized=police([(1000,3000)],8_000_000,2000)
 verify('packet larger than bucket cannot conform even after idle',not oversized[0]['admitted'])
 continuous=police([(0,1000),(1,1000),(2,1000)],8_000_000,1000)
 verify('one packet per millisecond conforms at eight megabits',all(x['admitted']for x in continuous))
 equality=fifo([(0,1000),(1,1000)],8_000_000,1000)
 verify('same-time completion frees queue space before arrival',all(x['admitted']for x in equality))
 fractional=fifo([(0,700)],8_000_000,1000)
 verify('serialization preserves sub-millisecond result',fractional[0]['finishMs']==0.7)
 classification=[{'dscpEF':a,'authorizedSource':b,'matchAny':match([a,b],'any'),'matchAll':match([a,b],'all')}for a,b in [(False,False),(False,True),(True,False),(True,True)]]
 verify('any accepts either criterion',[x['matchAny']for x in classification]==[False,True,True,True])
 verify('all requires both criteria',[x['matchAll']for x in classification]==[False,False,False,True])
 short=backlog(150_000_000,100_000_000,200);long=backlog(150_000_000,100_000_000,20_000)
 verify('short excess creates 1.25 MB backlog',short=={'queuedBytes':1250000.0,'drainMsIfArrivalsStop':100.0})
 verify('twenty-second excess creates 125 MB backlog',long=={'queuedBytes':125000000.0,'drainMsIfArrivalsStop':10000.0})
 verify('no positive backlog when service exceeds arrival',backlog(80_000_000,100_000_000,200)['queuedBytes']==0)
 for label,args in [('negative time',[(-1,1000)]),('unordered times',[(2,1000),(1,1000)]),('zero packet',[(0,0)])]:
 try:police(args,8_000_000,2000)
 except ValueError:checks.append('rejects '+label)
 else:raise AssertionError(label)
 return {'checkedAt':datetime.datetime.now(datetime.timezone.utc).isoformat,'scriptSha256':hashlib.sha256(pathlib.Path(__file__).read_bytes).hexdigest,'checks':checks,'inputs':{'rateBps':8000000,'bucketBytes':2000,'arrivals':arrivals},'policer':policed,'fifo4000':wide,'fifo2000':small,'oversized':oversized,'classification':classification,'fluidBacklog':{'short':short,'long':long},'assumptions':['Original deterministic teaching models, not IOS XE execution or physical measurements','Decimal rates: bps means bits/second; queue/bucket sizes mean bytes','Policer: one initially full bucket, continuous refill, drop when a whole packet cannot conform, no remarking','FIFO: fixed service rate without token credit or priority; capacity includes in-service packet; same-time departures happen first','Fluid backlog: constant offered and service rates, no feedback or losses; drain time assumes arrivals stop','No TCP dynamics, packet overhead, vendor scheduler, microburst capture or SLA measurement']}

if __name__=='__main__':
 report=run;pathlib.Path(sys.argv[1]).write_text(json.dumps(report,indent=2)+'\n')
 print(json.dumps({'checks':len(report['checks']),'modelOnly':True,'networkAccess':False}))
IN PRACTICE

In the 8-Mb/s model, four 1,000-byte packets need 4 ms of service; a larger queue does not reduce that work.

Common pitfalls

Confusing bits and bytes; average as proof of no bursts; assuming infinite queues; simulation as a hardware measurement.

Related topics: QoS: classification, trust and contracts · Architecture and surviving capacity

Take this idea with you

State units and assumptions, and accept loss and delay using evidence matching the service.

Create account

Reference: Compare Traffic Policing and Traffic Shaping to Limit Bandwidth · 350-401 ENCOR v1.2, effective 2026-03-19; core component of CCNP Enterprise

CCNP® and Cisco® are registered trademarks of Cisco Systems, Inc. and/or its affiliates. bigsavant.com is an independent preparation platform and is not affiliated with, associated with, sponsored, authorised or endorsed by Cisco. Content and questions are original, are not official exam questions, and completing our tests does not award or guarantee any certification. Names are used only to identify the subject. All other trademarks belong to their respective owners.