Listener and route — bind and match

A listener is the socket the proxy binds (an address+port); a route is one row in an ordered match table — the first row that matches decides the destination, so order is meaning, not decoration.

Previously

Reading method and path is only useful if the proxy has a structured table that says 'this kind of request goes there' — and that table is two named pieces: a listener and a route.

Scene 04

Listener and route — bind and match

  1. Watch
  2. Try it
  3. Predict
  4. Capture
TEST REQUESTGET /checkout/cartx-canary: trueListener (port 8080)0.0.0.0SIDECAR PROXY · ROUTE TABLEfirst match wins · top-to-bottomorder1/MATCHprefix=/checkout→DESTcheckout-v1MATCH2hMATCHheader x-canary: true→DESTcheckout-v23*MATCHmatch /*→DESTdefault-svcROUTED TOcheckout-v1First match wins: row 1 → checkout-v1
↑ listener — socket bound to (0.0.0.0, 8080) where requests arrive
↓ ordered routes — first match wins, every row below is unreachable
← this route matched first → exit toward its destination
What to watch for

A test request GET /checkout/cart (with header x-canary: true) hits the listener on port 8080. The proxy walks the route table top-to-bottom. The first matching row glows green and the request exits toward its named destination.

Implementation

Highlighted lines are the ones running in the diagram right now.

Listener.bind(address, port)
the socket the proxy listens on — LDS pushes this
def bind_listener(cfg):
sock = listen(addr=cfg.address, port=cfg.port)
# filter chain: TLS? HTTP? raw TCP? — picks HCM here.
chain = [http_connection_manager(routes=cfg.routes)]
while conn := sock.accept():
chain.handle(conn) # parse req, then route_match
RouteTable.match(req) # first-match-wins
walk the rows top-to-bottom; return on the first hit
def match(req, routes):
for route in routes: # ORDERED — RDS order is policy
if matches(req, route.match):
return route.destination
return DEFAULT_REJECT # 404 / direct_response
def matches(req, m):
if m.kind == 'wildcard': return True
if m.kind == 'prefix': return req.path.startswith(m.value)
if m.kind == 'header':
name, want = m.value.split(':', 1)
return req.headers.get(name.strip()) == want.strip()
match(GET /checkout/cart, x-canary: true)
same request, three orderings, three destinations
# ordering 0: wildcard on top
[wildcard '/*', prefix '/checkout', header 'x-canary'] -> default-svc
# ordering 1: prefix on top (canary unreachable below)
[prefix '/checkout', header 'x-canary', wildcard '/*'] -> checkout-v1
# ordering 2: header on top (canary works)
[header 'x-canary', prefix '/checkout', wildcard '/*'] -> checkout-v2

Where this sits in Build a Service Mesh (Envoy / Istio style)

Scene 04 of 13. A listener accepts on a port; an ordered route table picks a destination on the first match. Reorder the rules and the same request lands somewhere else.

Up next. A route's destination is a name like checkout-svc, but behind that name are many replicas — and the proxy has to pick one for every request.

All 13 scenes in Build a Service Mesh (Envoy / Istio style) · Every curriculum

Built with Arqly
Every scene in Build a Service Mesh (Envoy / Istio style) builds on the one before it.All 13 Build a Service Mesh (Envoy / Istio style) scenes