Skip to content

Commit f123ce1

Browse files
thomas-manginclaude
andcommitted
Refactor: FlowSpec NLRI to packed-bytes-first pattern
Convert IPrefix4, IPrefix6, and Flow classes to store wire format bytes and unpack on demand: - IPrefix4: __init__(packed) + make_prefix4() factory - IPrefix6: __init__(packed, offset) + make_prefix6() factory - Flow: __init__(packed, afi, safi, action) + make_flow() factory - Lazy rule parsing via rules property - _packed_stale flag for invalidation on add() - _rd_override for RD set via setter Update call sites in configuration/flow/ to use new factories. Update tests to use factory methods. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f233dbd commit f123ce1

File tree

6 files changed

+386
-207
lines changed

6 files changed

+386
-207
lines changed

plan/packed-bytes/progress.md

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -238,19 +238,45 @@ cached instances for identical parameter combinations.
238238

239239
---
240240

241-
## Wave 6: NLRI Types 🔄 PARTIAL
241+
## Wave 6: NLRI Types ✅ COMPLETE
242242

243243
| File | Class | Status | Notes |
244244
|------|-------|--------|-------|
245245
| `nlri/cidr.py` | CIDR || `__init__(self, nlri: bytes)` |
246246
| `nlri/inet.py` | INET || `__init__(self, packed: bytes, ...)` |
247247
| `nlri/label.py` | Label || `__init__(self, packed: bytes, ...)` |
248248
| `nlri/ipvpn.py` | IPVPN || `__init__(self, packed: bytes, ...)` |
249-
| `nlri/vpls.py` | VPLS || `__init__(self, packed: bytes, ...)` |
250-
| `nlri/rtc.py` | RTC | 🔄 | Origin as packed; RT needs `negotiated` |
251-
| `nlri/flow.py` | Flow | ⊘ N/A | Builder pattern - excluded by design |
252-
| `nlri/flow.py` | IPrefix4 | ⊘ N/A | FlowSpec component - excluded |
253-
| `nlri/flow.py` | IPrefix6 | ⊘ N/A | FlowSpec component - excluded |
249+
| `nlri/vpls.py` | VPLS || `__init__(packed)` + `make_vpls()`, `make_empty()` factories |
250+
| `nlri/rtc.py` | RTC || `__init__(packed_origin, rt)` + `make_rtc()` factory |
251+
| `nlri/flow.py` | Flow || `__init__(packed, afi, safi, action)` + `make_flow()` factory |
252+
| `nlri/flow.py` | IPrefix4 || `__init__(packed)` + `make_prefix4()` factory |
253+
| `nlri/flow.py` | IPrefix6 || `__init__(packed, offset)` + `make_prefix6()` factory |
254+
255+
#### RTC Design Note (2025-12-04)
256+
257+
RTC uses a hybrid pattern:
258+
- `packed_origin: bytes | None` - 4 bytes packed ASN, stored as wire bytes
259+
- `rt: RouteTarget | None` - stored as object (RT unpacking requires `negotiated`)
260+
- `origin` property unpacks ASN from `_packed_origin`
261+
- `make_rtc(origin, rt)` factory creates instances from semantic values
262+
263+
This is the best we can achieve because RouteTarget.unpack_attribute() requires negotiated context.
264+
265+
#### Flow Design Note (2025-12-04)
266+
267+
Flow uses a hybrid pattern with lazy rule parsing:
268+
- `_packed: bytes` - stores wire format bytes (excluding length prefix)
269+
- `_rules_cache: dict | None` - parsed rules, lazily populated on first access
270+
- `_packed_stale: bool` - marks when packed needs recomputation
271+
- `_rd_override: RouteDistinguisher | None` - RD set via setter
272+
273+
Key methods:
274+
- `__init__(packed, afi, safi, action)` - create from wire bytes
275+
- `make_flow(afi, safi, action)` - factory for builder mode (config/API)
276+
- `rules` property - lazy parses from `_packed` on first access
277+
- `rd` property - returns `_rd_override` if set, else extracts from `_packed`
278+
- `add(rule)` - adds rule, marks `_packed_stale=True`
279+
- `_pack_nlri_simple()` - returns stored bytes if valid, else recomputes
254280

255281
---
256282

@@ -323,12 +349,12 @@ cached instances for identical parameter combinations.
323349
| Wave 3 | ~20 | 0 | 0 | 0 | ~20 |
324350
| Wave 4 | ~50 | 0 | 0 | 3 | ~53 |
325351
| Wave 5 | 5 | 0 | 0 | 0 | 5 |
326-
| Wave 6 | 5 | 1 | 0 | 3 | 9 |
352+
| Wave 6 | 9 | 0 | 0 | 0 | 9 |
327353
| Wave 7 | ~20 | 0 | 0 | 0 | ~20 |
328354
| Wave 8 | 6 | 0 | 0 | 0 | 6 |
329-
| **TOTAL** | **~120** | **1** | **0** | **7** | **~128** |
355+
| **TOTAL** | **~124** | **0** | **0** | **4** | **~128** |
330356

331-
**Completion: ~99%** (120 done + 1 partial out of ~121 convertible classes)
357+
**Completion: 100%** (all convertible classes done)
332358

333359
---
334360

0 commit comments

Comments
 (0)