code wiki / _hdl_build / nx_route_table.nx

nx_route_table.nx source

↩ module page · 128 lines · 5351 B

1// nx_route_table.nx -- the S-CLASS DATA-DRIVEN ROUTE MATCHER (the LOGIC core that RETIRES the hardcoded 2// if-cascade). PURE: a route TABLE (data) + a request (host, path) -> the matched (backend port, mode). NO 3// hardcoded routes, NO IO, NO sockets. Semantics match the SOTA (nginx/Envoy/HAProxy/ingress, banked in 4// knowledge/library/route_*): EXACT host beats wildcard '*'; LONGEST path-prefix wins; BOUNDARY-SAFE (`/gen` 5// matches `/gen` and `/gen/*` but NEVER `/generated`); per-route MODE. Operator: "fix all this hardcoding and 6// tight coupling especially on routing ... get it to s class exceed, not the garbage f-level stuff." 7// Table row format (one per line, space-delimited; '#'=comment): <host|*> <path-prefix> <port> <mode> 8// modes: buffered|stream|gated. license_tier: ORIGINAL 9import "nx_syscalls.nx" 10const RT_MAGIC_1000000: i64 = 1000000 11 12const RT_BUFFERED: i64 = 0 13const RT_STREAM: i64 = 1 14const RT_GATED: i64 = 2 15 16func rt_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 17 18func rt_eol(b: *u8, n: i64, st: i64) -> i64 { 19 var i: i64 = st 20 var f: i64 = 0 21 while f == 0 { if i >= n { f = 1 } else { if (b[i] as i64) == 10 { f = 1 } else { i = i + 1 } } } 22 return i 23} 24 25// split b[ls..le) on spaces into up-to-maxf (offs,lens) absolute slices. returns field count. 26func rt_split(b: *u8, ls: i64, le: i64, offs: *i64, lens: *i64, maxf: i64) -> i64 { 27 var nf: i64 = 0 28 var i: i64 = ls 29 while i < le { 30 var sk: i64 = 1 31 while sk == 1 { if i >= le { sk = 0 } else { if (b[i] as i64) == 32 { i = i + 1 } else { sk = 0 } } } 32 if i < le { 33 let st: i64 = i 34 var sc: i64 = 1 35 while sc == 1 { if i >= le { sc = 0 } else { if (b[i] as i64) == 32 { sc = 0 } else { i = i + 1 } } } 36 if nf < maxf { offs[nf] = st; lens[nf] = i - st; nf = nf + 1 } 37 } 38 } 39 return nf 40} 41 42func rt_slice_atoi(src: *u8, off: i64, len: i64) -> i64 { 43 var v: i64 = 0 44 var i: i64 = 0 45 while i < len { 46 let c: i64 = src[off + i] as i64 47 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } 48 i = i + 1 49 } 50 return v 51} 52 53// slice == null-terminated tok? 54func rt_tok_eq(src: *u8, off: i64, len: i64, tok: *u8) -> i64 { 55 let tl: i64 = rt_slen(tok) 56 if tl != len { return 0 } 57 var i: i64 = 0 58 while i < len { if (src[off + i] as i64) != (tok[i] as i64) { return 0 } i = i + 1 } 59 return 1 60} 61 62// slice a[ao..ao+al) == slice b[bo..bo+bl)? 63func rt_slice_eq(a: *u8, ao: i64, al: i64, b: *u8, bo: i64, bl: i64) -> i64 { 64 if al != bl { return 0 } 65 var i: i64 = 0 66 while i < al { if (a[ao + i] as i64) != (b[bo + i] as i64) { return 0 } i = i + 1 } 67 return 1 68} 69 70// BOUNDARY-SAFE prefix: does path[0..pn) start with pre[po..po+prel) AT A PATH BOUNDARY? 71// true iff pre is a char-prefix AND (path==pre OR the next path char is '/'). So "/gen" matches "/gen" and 72// "/gen/x" but NOT "/generated". (route prefixes are authored WITHOUT a trailing slash.) 73func rt_prefix_boundary(path: *u8, pn: i64, pre: *u8, po: i64, prel: i64) -> i64 { 74 if prel > pn { return 0 } 75 var i: i64 = 0 76 while i < prel { if (path[i] as i64) != (pre[po + i] as i64) { return 0 } i = i + 1 } 77 if pn == prel { return 1 } 78 if (path[prel] as i64) == 47 { return 1 } 79 return 0 80} 81 82func rt_mode_code(rt: *u8, off: i64, len: i64) -> i64 { 83 if rt_tok_eq(rt, off, len, "stream" as *u8) == 1 { return RT_STREAM } 84 if rt_tok_eq(rt, off, len, "gated" as *u8) == 1 { return RT_GATED } 85 return RT_BUFFERED 86} 87 88// THE MATCHER: best route for (host,path) over the table rt[0..n). EXACT host beats '*'; among those, LONGEST 89// path-prefix wins (boundary-safe). Sets port_out/mode_out, returns 1 if matched / 0 if none. 90func rt_match(rt: *u8, n: i64, host: *u8, hn: i64, path: *u8, pn: i64, port_out: *i64, mode_out: *i64) -> i64 { 91 let offs: *i64 = sys_mmap(64) as *i64 92 let lens: *i64 = sys_mmap(64) as *i64 93 var best_score: i64 = 0 - 1 94 var best_port: i64 = 0 95 var best_mode: i64 = 0 96 var cur: i64 = 0 97 while cur < n { 98 let le: i64 = rt_eol(rt, n, cur) 99 var ok_line: i64 = 1 100 if le <= cur { ok_line = 0 } 101 if ok_line == 1 { if (rt[cur] as i64) == 35 { ok_line = 0 } } 102 if ok_line == 1 { 103 let nf: i64 = rt_split(rt, cur, le, offs, lens, 8) 104 if nf >= 4 { 105 var hmatch: i64 = 0 106 var exact: i64 = 0 107 if rt_tok_eq(rt, offs[0], lens[0], "*" as *u8) == 1 { hmatch = 1 } 108 if hmatch == 0 { if rt_slice_eq(rt, offs[0], lens[0], host, 0, hn) == 1 { hmatch = 1; exact = 1 } } 109 if hmatch == 1 { 110 if rt_prefix_boundary(path, pn, rt, offs[1], lens[1]) == 1 { 111 var score: i64 = lens[1] 112 if exact == 1 { score = score + RT_MAGIC_1000000 } 113 if score > best_score { 114 best_score = score 115 best_port = rt_slice_atoi(rt, offs[2], lens[2]) 116 best_mode = rt_mode_code(rt, offs[3], lens[3]) 117 } 118 } 119 } 120 } 121 } 122 cur = le + 1 123 } 124 if best_score < 0 { return 0 } 125 port_out[0] = best_port 126 mode_out[0] = best_mode 127 return 1 128}