Wait, Do We Still Need Network Engineers? And a Little SRv6
Fact number one: I wanted to write a small note about SRv6. Not even about SRv6 as a protocol, really, but about the road the industry travelled from plain old LDP to a world where an IPv6 address can be both a destination and an instruction.
Disclaimer #1
Before going any further, open Two Labels, One SRH, and One Very Annoying
rp_filterand skim it for five minutes. That article is the polished technical result I originally wanted.The article you are reading now is about how that result was produced — and about the increasingly awkward question of who, exactly, did the producing.
Fact number two: while scrolling through LinkedIn — the world’s best-organised vanity fair — I noticed that every second person had acquired an AI prefix.

And then there was my favourite:

An AI influencer. Magnificent. Apparently I also needed to write something about AI — or have AI do something, then write about the fact that it had done it.
Disclaimer #2
This article contains a frankly unreasonable amount of text, and most of the material inside the expandable sections was generated by AI.
There are three ways to read it:
- Open the “AI reasoning” sections if you care about how an agent approached a long, stateful infrastructure task.
- Open the “lab note” sections if you want a practical learning path from Linux IP forwarding through OSPF, LDP, L3VPN, TE, SR-MPLS, SR Policy, and SRv6.
- Ignore every expandable section and read only my commentary. That version is mostly about humans, robots, and the dangerous possibility that the boundary between them is now a formatting choice.
The Lab I Was Too Lazy to Configure
I built the following topology in my beloved PNETLab:

There are two provider edges, four core routers, and four customer machines. RED and BLUE are separate tenants. The intended story is familiar: deliver traffic inside each customer network, keep the customers isolated, and evolve the transport mechanism one layer at a time.
The problem was that I did not feel like configuring any of it.
So the AI could do it.
My Real Problem with AI
My biggest problem with AI was never that the tools were weak. It was that there were too many of them.
For a long time I behaved like Buridan’s donkey: I sat between twenty impressive products, chose none of them, and quietly used free DeepSeek because it was already open in a browser tab. Eventually I decided that a ChatGPT subscription cost less than a respectable evening of pizza and crossed into a new plane of existence.
Chat was useful. Suspiciously useful. I could feel my productivity expanding in real time.
But there was also Codex.
Several freshly minted AI people told me the same thing: try it once and you will not want to work without it. This sounded less like a product recommendation and more like the opening scene of a public-health documentary, but I tried it.
They were not entirely wrong.
The uncomfortable part is that working with an agent is work. You spend time describing what you want, constructing a harness, limiting destructive freedom, deciding what counts as evidence, and teaching the agent not to celebrate too early. Sometimes that takes longer than doing the first version yourself.
The promise is not “zero effort”. The promise is leverage.
Building a Primitive Network Agent
I am a Windows person, so I opened the desktop app and created a project.

The project got a local working folder. That folder would contain inventory, credentials, diagrams, notes, scripts, and whatever code the agent created while solving the task.
Then I wrote an AGENTS.md file. Not because I had suddenly become an elite AI builder, but because an artificial intelligence is still artificial. If you do not describe its job, boundaries, and definition of “done”, it will invent all three with great confidence.
The adapted AGENTS.md: the contract for our network engineer
Who you are
You are the network engineer-researcher responsible for building and explaining an educational MPLS and Segment Routing lab. You are not a configuration generator. Your job is to inspect reality, form hypotheses, make controlled changes, and prove what happened.
What we are building
Start from a clean Linux topology and evolve it in explicit stages:
- Reconstruct and document the physical data-plane topology.
- Build an IPv4 point-to-point foundation.
- Add an OSPF transport underlay.
- Add MPLS forwarding and LDP.
- Build isolated RED and BLUE MPLS L3VPN services.
- Explore Traffic Engineering honestly, including platform limitations.
- Add SR-MPLS and an explicit SR Policy.
- Build an IPv6 underlay and demonstrate SRv6.
- Finish a working RED L3VPN over SRv6 while retaining BLUE as a control service.
Do not assume the network exists
Hostnames, interface names, addressing, cabling, installed packages, kernel features, routing daemons, and protocol state must be observed. Inventory is a source of access data, not proof that the data plane matches a drawing.
Never guess an address from a pattern. Never infer a link merely because two device names look adjacent. Never call a protocol “working” because configuration lines exist.
The main rule
Every meaningful claim needs evidence from the relevant plane:
- configuration proves intent;
- protocol state proves control-plane convergence;
- FIB or LFIB proves installation;
- packet capture proves encapsulation and forwarding;
- end-to-end traffic proves the service experienced the result.
No single one of those substitutes for all the others.
How to make changes
- Preserve the management network.
- Prefer the smallest reversible change.
- Inspect state before and after mutation.
- Keep a reproducible source of truth.
- If a command can interrupt access or alter host security, explain the risk first.
- If a platform cannot implement a requested feature, say so. Build an explicitly labelled demonstration only if it still teaches the right mechanism.
How to report failure
A failed experiment is useful when the failure boundary is precise. State what was expected, what was observed, where the packet or state disappeared, which hypotheses were tested, and what remains unproven.
Do not turn “I saw an SRH” into “SRv6 L3VPN works” when the decapsulated packet never left the far PE.
How to explain technology
Explain why the next layer exists before configuring it. Relate each new mechanism to the limitation of the previous one. Use small diagrams, selected commands, and real evidence. Avoid mile-long configuration dumps unless they are needed for reproduction.
Personality
Be technically stubborn, curious, and willing to disagree. Admit mistakes. Do not flatter the operator. A useful lab partner is allowed to say “your assumption is wrong” and “my previous answer skipped a stage”.
Naturally, I wrote all of that myself. Obviously.
Then I spoke to the thing.

It was alive. Or at least it had read the file and had started using phrases such as “network engineer-researcher”, which is close enough.
I gave it a trick question.

Good answer. There was no inventory, so it did not scan random addresses or hallucinate an SSH alias. It inspected the project, explained the missing evidence, and stopped.
The desktop interface separated reasoning, commands, and final answer:


Then I added a very human-readable inventory and a credentials file. No grand automation schema, just names and management IPv6 addresses. I asked whether that was enough.

Codex connected to all ten hosts and reported an almost perfectly blank lab: management IPv6 worked, data interfaces were down and unnumbered, forwarding was disabled, FRR was absent, and MPLS kernel state was not yet present. It also found a typo in my inventory: one machine described as PE-2-Left identified itself as PE-2-Right.
That was a small but important moment. The inventory enabled access; observation corrected the inventory.
Codex reasoning: what can be claimed about an empty lab?
The agent started with read-only commands on every host: hostname, ip -br link, ip -br address, routing tables, forwarding sysctls, FRR service state, and availability of LLDP tools.
Its conclusion was deliberately narrow:
We have ten Linux machines with a working management network, but the data plane does not yet exist. The silent data interfaces do not reveal cabling. The next rational step is to recover L1 from the hypervisor or bring up only the candidate data ports and use LLDP.
This is the sort of answer that looks obvious after someone has done the thinking. The important part is what it did not do: it did not treat the PNETLab drawing as live state, and it did not configure IP before knowing which interface faced which neighbour.
First, Make a Diagram. Then Discover Why It Is Wrong
I asked Codex to draw the topology.

It generated editable Draw.io XML. Codex is, after all, a coding agent; XML is code wearing business-casual clothes.

The first diagram showed only what was known: management reachability, hosts, and unknown data ports.

It was honest. It was also useless to anyone who wanted to understand the forwarding path.
So I gave feedback: bring up the data interfaces, run LLDP, discover both ends of every link, label ports, use recognisable network icons, and remove the management clutter.

Twelve minutes later:


I compared the result with my original drawing and thought it had lost the link between P-1 and P-3. A manual LLDP check showed the neighbour. The line had merely merged visually with two other links.
In other words, the robot was right and the senior engineer was defeated by line geometry.
I gave it an old diagram as a style reference:

It produced a more recognisable network map, I asked for one final correction, and then the senior engineer made his essential contribution: moving a few objects by hand.



This, as every architect knows, is what seniority looks like.
A Plan Appears
Before configuring anything, I asked the agent to remind me what we were actually doing.

Its plan and mine had the same shape:
IPv4 → OSPF → LDP → L3VPN → TE → SR-MPLS → SR Policy → SRv6
That sequence matters. A long-running agent becomes dramatically more useful when the problem is not “configure SRv6” but “build a chain of independently proven states, and do not advance when one link is imaginary”.
Stage 1 — The IPv4 Foundation
My instruction was intentionally broad: execute the plan in large stages and leave a separate educational note after each one.

Codex allocated one /31 per verified point-to-point link from 10.10.0.0/27, preserved ens3 for management, enabled IPv4 forwarding only on routers, and saved the configuration without casually bouncing the management interface.
Codex reasoning and selected evidence: Stage 1
The agent first checked whether systemd-networkd or NetworkManager owned the interfaces and inspected the existing Netplan files. This was not ceremony. A correct address applied through the wrong configuration system is a temporary state pretending to be infrastructure.
The twelve verified links received /31 networks. PE and P routers got forwarding; customer PCs did not. After writing a separate data-plane Netplan file, the agent used netplan generate before applying changes and verified every endpoint with ip -br -4 address and connected-route lookups.
The boundary of success was explicit: direct neighbours had to ping; remote nodes did not have to. There was no IGP yet, so the absence of distant routes was correct behaviour.
That may sound pedantic. It is also how you avoid debugging OSPF with a broken cable, or debugging MPLS with a broken /31.
Stage 2 — OSPF: Give the Core a Memory
I asked what stage two meant.

FRR was not installed. The agent installed it on six routers, created stable /32 loopbacks from 10.255.0.1 through 10.255.0.6, enabled OSPFv2 only on core links, and kept the customer-facing interfaces passive.
Lab note: OSPF transport
The expected neighbour count was derived before the check: two adjacencies on each PE, three on each P router, sixteen directed adjacency records in total. All reached Full.
PE-1 learned all remote loopbacks and had equal-cost paths towards PE-2. A representative route looked like this:
O>* 10.255.0.6/32 [110/3] via 10.10.0.1, ens4
* via 10.10.0.3, ens5
Then the agent tested the data plane, not merely the LSDB:
ip route get 10.255.0.6 from 10.255.0.1
ping -I 10.255.0.1 -c 4 10.255.0.6
The ping returned four out of four, and the selected next hop matched an OSPF path. Only at that point did “the OSPF transport works” become a defensible sentence.
Stage 3 — MPLS and LDP
I asked the most sophisticated architectural question available to me:

MPLS forwarding was enabled only on core-facing interfaces. LDP sessions used the stable loopbacks, and the agent inspected the LIB and LFIB for push, swap, and implicit-null behaviour.
The stage took longer than expected. I asked why.

One SSH command had used a template IPv6 prefix instead of the exact management address in the inventory. Then a packet capture waited for traffic that had already been sent and sat there with the quiet confidence of a command that will never return.

I asked for a solemn promise.

Lab note: proving LDP forwarding
Control-plane checks showed LDP peers over the transport loopbacks and label bindings for remote FECs. The kernel MPLS routes showed the forwarding operations selected at each hop.
The useful proof was a capture on P-2 while PE-1 pinged the remote PE loopback:
ethertype MPLS unicast (0x8847)
MPLS (label 22, tc 0, [S], ttl 64)
10.255.0.1 > 10.255.0.6: ICMP echo request
That packet established the full chain: the ingress PE pushed a label, a transit P router received an MPLS frame, and the far PE returned the traffic. The result was not “LDP neighbours exist”. It was “the LDP-distributed transport labels carry packets”.
Stage 4 — Two Customers, One Core, No Accidental Friendship
The next layer was MPLS L3VPN.

The agent created RED and BLUE VRFs on both PEs, assigned customer-facing interfaces, established MP-BGP VPNv4 between the PE loopbacks, used distinct RDs and matching route targets, and kept the services out of the provider IGP.
At one point the interface reported that it had read Lab_Inventory and Lab_Creds, which was reassuring after the previous creative IPv6 address.

I also noticed an odd transport trick: Codex encoded Netplan YAML as base64, sent it through SSH, and decoded it on the host. It looked alarming for approximately four seconds, after which it looked like a perfectly practical way to stop three layers of quoting from eating indentation.

Lab note: MPLS L3VPN and the first lesson in state drift
MP-BGP carried VPNv4 routes between the PE loopbacks. RED and BLUE used separate route targets and separate VRF tables. RED-PC-1 could reach RED-PC-2, BLUE-PC-1 could reach BLUE-PC-2, and RED could not reach BLUE.
The packet stack contained two labels: an outer transport label distributed by LDP and an inner VPN label identifying the service at the far PE. Transit P routers knew nothing about the customer prefixes.
The most instructive problem was not MPLS. A later netplan apply reset addresses that had been added manually to VRF-facing interfaces, so VPN export disappeared. The network did not break “because SRv6 is difficult”. It broke because two configuration sources believed they owned the same state.
That lesson survived every later stage: decide which system is authoritative before you ask an agent to make the next change.
Stage 5 — Traffic Engineering, With the Marketing Removed
Shortest-path routing is excellent until the shortest path is not the path you want. I asked Codex to add a Traffic Engineering chapter and explain what practical problem it solved.


OSPF TE advertisements could describe bandwidth and link attributes and populate a Traffic Engineering Database. But our FRR version did not provide a complete RSVP-TE signaling and reservation plane.
Codex refused to call the result “working RSVP-TE”. This is one of the reasons the experiment was useful.

Codex reasoning: a TED is not a tunnel
A path computation element can read a Traffic Engineering Database and calculate a constrained path: minimum bandwidth, excluded nodes, affinities, disjointness, latency, or any policy the model understands.
But path computation does not install forwarding state by magic. Classic RSVP-TE still needs signaling on the label-switching routers. The ingress sends Path, each hop checks resources and allocates state, and the egress returns Resv. That process supplies reservation, pre-emption, and a clear failure when constraints cannot be met.
Our lab had TE information, an MPLS data plane, and services that could be steered. It did not have a standards-complete RSVP-TE daemon. A Python controller could have calculated a path and programmed static labels, but calling that RSVP-TE would have been educational fraud.
So we documented the boundary and moved to Segment Routing, which was actually implementable on this stack.
Stage 6 — SR-MPLS: Labels Become Instructions
I asked whether Segment Routing was next, and why it mattered when Traffic Engineering already existed.

Codex created a diagram without being asked. I have preserved the punctuation and, more importantly, corrected the labels.

SR-MPLS kept the existing MPLS forwarding plane but replaced per-tunnel signaling in the core with segment instructions chosen at the ingress. Node SIDs represented routers; a stack of SIDs represented a path.
During this stage the safety review paused a change to rp_filter.

This was funny because root access and a small mountain of configuration had not upset it. Reverse-path filtering, however, apparently looked like the moment the hackers would finally enter my educational lab.
Lab note: SR-MPLS alongside LDP
The agent enabled Segment Routing in the IGP and assigned stable Node SIDs from the SR Global Block. OSPF advertised the prefix-SIDs, the kernel installed MPLS routes for remote segments, and packet captures showed the chosen label stack.
The transition did not require a flag day. LDP and SR-MPLS could coexist while one service moved to the new transport behaviour. That coexistence made BLUE useful as a control: it continued to use the previously proven mechanism while RED became the experimental service.
The limitation was equally important: SR removes the need for RSVP signaling, but a segment list does not reserve bandwidth. If reservation is a requirement, something else must own admission and resource state.
Stage 7 — The Step the Agent Forgot: SR Policy
After several hours of editing I had forgotten where we were, so I asked Codex for the next logical step.

Something felt missing. Its earlier note had mentioned SR Policy.

The agent admitted the mistake. We first built an explicit SR Policy over the existing SR-MPLS domain and steered RED through it while BLUE remained on ordinary LDP.

Lab note: an explicit path over SR-MPLS
pathd created a local explicit candidate path on the ingress PE. The segment list described the intended route through selected Node SIDs. Policy routing placed RED traffic into the policy; BLUE remained the baseline.
The evidence had three layers:
- the policy was operational in
pathd; - the kernel route for RED selected the SR policy;
- a transit capture showed the expected MPLS segment stack and the chosen corridor.
This stage made the later SRv6 comparison much cleaner. We had already separated “how the ingress expresses path intent” from “what the forwarding plane uses to carry that intent”.
Stage 8 — SRv6, and the Value of an Honest Failure
Now we could finally make the obvious request.

I left the laptop and went for a walk in the woods. Intuition suggested that this would not be a four-minute stage.
Codex spent forty-four minutes building a parallel IPv6 underlay, checking kernel and FRR capabilities, installing SID behaviour, and trying to move RED. Then it stopped without a clean final answer. Maybe the usage window ended. Maybe the robot also went to the woods.
I asked it to continue.

Thirty-two minutes later it produced an honest diagram:

The IPv6 underlay worked. An IPv4 RED packet was encapsulated with IPv6 and an SRH. A core capture saw that packet reach PE-2. The local SID matched. But after End.DT4 decapsulation, the packet did not leave through the RED VRF.
That is not a working SRv6 L3VPN.
It is also much more useful than a screenshot of a green route table followed by a claim that everything is fine.
Codex reasoning: narrowing the SRv6 failure boundary
The agent first separated platform capability from lab configuration. It checked kernel SRv6 sysctls, available seg6local actions, FRR version and daemons, IPv6 forwarding, locator reachability, and the policy-routing rules that selected the local SID table.
Two Linux-specific traps appeared:
- An FRR setting could overwrite IPv6 forwarding and silently break transit.
- A broad local locator route could win lookup before the more specific local-SID action unless the SID table and rules were designed carefully.
After correcting those issues, a capture proved that the SRH reached the far PE and the correct SID was selected. The remaining gap was after decapsulation, at the handoff from the core context to VRF RED.
The first version of the stage note therefore said exactly that. Purple lines were proven packet paths; the final dotted hop was an expectation. No amount of confidence in the surrounding configuration could turn the dotted line solid.
Stage 9 — One More Stage Will Not Kill Us
Naturally, “almost works” was not a satisfying ending.

Codex built a miniature SRv6 lab inside network namespaces on one PE. That isolated Linux kernel behaviour from FRR, OSPF, BGP, and the accumulated history of the big topology. The upstream-style test passed, proving that the kernel could execute End.DT4.
The difference was reverse-path filtering.
After decapsulation, Linux validated the source address from the core context. That source was reachable only through the RED VRF. Strict RPF rejected the packet before the forwarding path had a chance to look correct.
Correcting rp_filter on the relevant data and VRF interfaces made the final hop work in both directions.

Lab note: closing the End.DT4 data-plane gap
The decisive troubleshooting method was differential testing.
First, a minimal namespace lab reproduced the intended architecture:
- two router namespaces connected by an IPv6 transport link;
- one RED VRF on each side;
- an
End.DT4SID bound to the far VRF; - IPv4 customer hosts behind the two routers;
- an SRv6 route that encapsulated the inner IPv4 packet.
That test passed. Therefore the feature existed in the kernel and the syntax was viable.
Next, the agent compared sysctls and lookup context between the isolated test and the large lab. The source of the decapsulated inner packet was valid inside VRF RED but not in the default table used by reverse-path validation. Strict RPF dropped it.
The fix was intentionally scoped to the lab’s service/data interfaces rather than the management interface. Once applied, the proof chain was complete:
ip route getselected the SRv6 encapsulation;- the core captured IPv6 plus SRH;
- PE-2 executed
End.DT4into table RED; - RED-PC-1 and RED-PC-2 exchanged bidirectional traffic;
- BLUE still worked over the MPLS L3VPN control path.
The best part was not the final ping. It was that we could explain precisely why the earlier ping failed.
The Managerial Question
At the end I asked the agent for a postmortem.

Its answer was better than “all tasks completed successfully”. The topology had been reconstructed from evidence; each layer depended on a proven previous layer; control-plane claims were backed by forwarding evidence; and the End.DT4 failure had not been hidden.
The hard problems were at the boundary between three systems that were each individually reasonable: the Linux kernel, VRF and policy routing, and FRR. A configuration could look correct in FRR, ip route get could select the SID, the packet could reach the PE — and the service could still fail after decapsulation.
State drift was the second class of failure. Netplan, manual commands, systemd units, and FRR all had opinions. If two of them owned the same fact, the lab could regress for reasons unrelated to the technology currently under investigation.
With hindsight, the agent would have done five things earlier:
- Define one reproducible owner for every piece of state.
- Run a minimal upstream-compatible
End.DT4test before debugging the full topology. - Record a version-and-capability matrix for kernel, FRR, iproute2, and daemons.
- Design RED as the migrating service and BLUE as the control service from the start.
- Resolve every management address from inventory instead of trusting a remembered prefix.
That is a credible engineering retrospective. It includes the robot’s own mistakes, which is more than can be said for some human retrospectives I have attended.
What Should a Fashionable Technical Blogger Do With All This?
If my only goal had been to publish a polished technical article, I could have opened a fresh chat in the same project and written one final prompt.

The result is the shorter English article. It explains the network evolution cleanly, uses the evidence gathered during the lab, and does not force the reader to watch an AI argue with rp_filter for an hour.
This article exists because that polished result hides the more interesting mechanism: the agent did not merely compose prose. It inspected a live lab, wrote scripts, changed ten machines, generated diagrams, maintained a staged plan, hit platform limitations, made mistakes, accepted corrections, created controlled experiments, and revised its own claims when the packet evidence disagreed.
GPT-5.6 Terra was the model behind that job. OpenAI describes it as the balanced GPT-5.6 model for everyday work. I did not use the newer GPT-6 Astra, and I did not need the strongest possible model to make the point.
The harness mattered at least as much as the model name.
Conclusions
-
Network engineers are no longer needed.
-
There is no point writing educational networking articles. A neural network can write them, build the lab, and produce the diagrams while you go to the woods.
-
This is slightly terrifying. I imagine the late eighteenth century also had people insisting that steam engines were just autocomplete for horses.
-
It is also exhilarating. LLMs are a multiplier: good judgment becomes more productive, and bad judgment reaches the wrong answer at industrial speed.
The first two conclusions are jokes. Mostly.
The serious conclusion is that the valuable part of network engineering is moving upward. Typing configuration was never the whole profession; it was merely the visible part. In this experiment the human contribution was choosing the learning sequence, defining safety boundaries, refusing a fake RSVP-TE result, catching a skipped SR Policy stage, demanding packet-level proof, and deciding that “the SRH reached PE-2” was not equivalent to “the VPN works”.
Codex supplied endurance, execution speed, breadth, and an almost worrying willingness to keep trying. I supplied intent, taste, suspicion, and the right to say “no, one more stage”.
That is not a clean division of labour. It is already blurry, and it will become blurrier.
But if the future network engineer is the person who specifies invariants, builds evidence loops, and supervises autonomous changes across real systems, then the profession is not disappearing.
It is becoming less about remembering commands and more about knowing what must be true when the commands are finished.