netloom 是一个使用 Go 编写的 SDN 软件项目。
netloom 由 net 和 loom 两部分组成。
net表示 network,也就是网络。loom表示织机,也有“编织”的意思。
所以 netloom 想表达的是:像织布一样去编排和组织网络,把原本分散的节点、链路、地址、路由和策略编织成一张可以统一描述、统一控制的虚拟网络。
这个名字更偏控制面语义,而不是单纯强调某个转发协议或某一种数据面实现。它适合用来描述一个负责 VPC、子网、IPAM、路由、网关和策略集成的 SDN 系统。
netloom 面向云网络和基础设施网络场景,目标是提供一套可编排的虚拟网络控制面,而不是依赖每台机器上的手工网络配置。
当前的方向包括:
- VPC 与虚拟网络抽象
- 子网与 IPAM 管理
- 逻辑交换与逻辑路由
- Gateway 与 NAT 编排
- 与 eBPF 安全策略能力集成
项目整体会保持简单、清晰、易维护:
- 使用 Go 实现控制面
- API 尽量小且行为明确
- 优先使用易读、易调试、易扩展的组件划分
当前的设计方向,接近 OVN + eBPF 的职责拆分。
netloom 负责网络控制面的核心能力:
- VPC 与子网建模
- IPAM
- 逻辑网络拓扑
- 路由意图表达
- Gateway 编排
- VIP、负载均衡挂载等服务连接能力
eBPF 负责安全与可观测性相关能力:
- 类安全组的策略执行
- 主机与工作负载级别的包过滤
- 基于连接状态的策略控制
- 流量观测与排障数据
也就是说:
netloom负责定义网络- eBPF 负责执行和观测安全策略
这和“Kube-OVN/OVN 负责虚拟网络,Cilium/eBPF 负责策略与观测”的整体思路接近,但 netloom 会保持自己的控制面边界和实现方式。
flowchart TB
subgraph Control["控制面"]
API["netloom API / Controller"]
MODEL["VPC / Subnet / IPAM / Route Model"]
API --> MODEL
end
subgraph VirtualNet["虚拟网络层"]
OVN["OVN / 虚拟网络后端"]
TOPO["Logical Switch / Logical Router / Gateway / NAT / VIP"]
OVN --> TOPO
end
subgraph Policy["安全与观测层"]
EBPF["eBPF Policy Engine"]
OBS["Flow / Events / Observability"]
EBPF --> OBS
end
subgraph Nodes["节点与工作负载"]
NODE1["Node A"]
NODE2["Node B"]
POD1["Workload A"]
POD2["Workload B"]
NODE1 --> POD1
NODE2 --> POD2
end
API --> OVN
API --> EBPF
TOPO --> NODE1
TOPO --> NODE2
EBPF --> NODE1
EBPF --> NODE2
style API fill:#4a90d9,color:#fff
style OVN fill:#27ae60,color:#fff
style EBPF fill:#e67e22,color:#fff
这张图表达的是:
netloom作为控制面,负责管理网络模型与编排逻辑。- OVN 风格的虚拟网络后端,负责实现逻辑交换、逻辑路由、Gateway、NAT 和 VIP。
- eBPF 负责策略执行和流量观测,不负责定义 VPC、子网或 IPAM。
- 工作负载同时受虚拟网络与 eBPF 策略影响,但两者的职责边界保持分离。
OVN ACL 本身很适合做分布式虚拟网络策略,但它不是唯一选择。
这里更倾向于这样分工:
- 虚拟网络、地址分配、VPC、路由等能力放在 SDN 控制面
- 更复杂的安全组能力交给 eBPF
这样做的好处是:
- 网络与安全职责边界更清晰
- 更容易获得更强的策略能力和观测能力
- 降低虚拟网络拓扑与安全实现细节之间的耦合
但这并不意味着系统一定更简单。混合架构会增加控制面和排障复杂度,所以两侧的边界必须保持明确,避免出现多套策略系统同时生效、相互覆盖的问题。
计划中的能力:
- 建模虚拟网络与子网
- 分配并回收 IP 地址
- 编排逻辑路由与 Gateway 行为
- 与 eBPF 策略引擎集成
- 提供清晰的面向运维和平台的接口
早期阶段的非目标:
- 从零重写所有数据面能力
- 在同一条路径上混用多套重叠策略系统
- 用过重的抽象隐藏控制面行为
netloom 目前仍处于早期阶段,整体架构还在持续收敛,但仓库里已经有一条可运行的端到端路径。
当前仓库已经包含:
- 控制面模型:VPC、Subnet、Endpoint、RouteTable、PolicyRoute、Gateway、NATRule、SecurityGroup、CIDRGroup;Endpoint 可声明 Cilium 风格 labels 与 named ports。
- 控制面一致性校验:拒绝重复的 VPC/Subnet/Endpoint/SecurityGroup/Gateway 等对象身份,拒绝 Endpoint IP 冲突,并在写入后端前校验 VPC、Subnet、安全组、remote-group 和 LoadBalancer 绑定子网等引用关系。
- Subnet 支持 Kube-OVN
excludeIps类似的exclude_cidrs保留地址段,控制面会拒绝 endpoint 使用被排除的地址,IPAM allocator 也会跳过这些 CIDR。 - OVN 风格拓扑后端:把逻辑交换、逻辑路由、静态 ECMP 路由、策略路由、Gateway、NAT、Service VIP 和 Provider Network 转换为带
external_ids所有权标记的批量ovn-nbctl事务;Gateway 覆盖集中式 chassis pin 与分布式网关元数据;NAT 覆盖 SNAT、DNAT、Floating IP (dnat_and_snat)、分布式 Floating IP 的logical_port/external_mac投影和 OVN NAT 端口映射;同名规则变更会按 desired state 替换旧 NAT 投影,并在控制面拒绝 EIP/端口冲突。 - Endpoint 可声明 Kube-OVN 风格静态
mac,OVN 后端会把 MAC+IP 写入 logical switch port addresses 和 port security;控制面会拒绝同子网重复 MAC 以及与网关 router port MAC 冲突的静态 MAC。 - Linux 工作负载 datapath:支持本机
/32//128地址路由、netns + veth多工作负载模式,以及基于 RPDB table/rule 的 IPv4/IPv6 策略路由下发;网卡/netns/策略路由操作默认使用vishvananda/netlink/netns后端执行,保留NETLOOM_LINUX_DATAPATH_BACKEND=command作为 shell 回退路径。 - Cilium 风格策略编译:把安全组规则编译为 endpoint-scoped policy map entry,并把
remote_cidr/remote_group/remote_endpoint_selector/remote_endpoint_expressions/remote_service/remote_cidr_group/remote_entities/remote_fqdns保留为可按真实 remote IP 匹配的 CIDR 元数据;重叠 CIDR 会按最长前缀选择更具体规则,精确 identity 命中优先于 CIDR fallback;安全组支持 CiliumenableDefaultDeny=false类似的default_deny_ingress=false/default_deny_egress=false,当 endpoint 绑定的所有安全组都显式关闭某方向 default deny 时,会生成最低优先级 wildcard allow,同时显式 drop/reject 仍优先生效;安全组支持 Kube-OVN 风格tier0/1,较小 tier 会先于较大 tier 生效,同一 tier 内 drop/reject 保持高于 allow/log,非零 rule priority 按 Kube-OVN1..16384范围校验并采用较小数值优先;remote_cidr支持 Ciliumexcept类似的except_cidrs差集展开;remote_group会展开为 endpoint identity 与精确成员 CIDR,remote_endpoint_selector/remote_endpoint_expressions会按 endpoint labels 展开为精确 endpoint identity/CIDR,并支持 Cilium/Kubernetes selector 的In、NotIn、Exists、DoesNotExist表达式,remote_service采用 CiliumtoServices类似的 egress 语义并展开为同 VPC LoadBalancer 的全部 VIP frontend、协议和端口,remote_cidr_group会按 desired-statecidr_groups展开为多条 CIDR 规则,CIDRGroup 支持 Cilium CIDRSet 风格的entries[].except_cidrs;remote_entities支持all/world/world-ipv4/world-ipv6/cluster/private/host/remote-node/none,其中world会展开为双栈默认 CIDR 扣除当前 VPC 子网后的外部地址集合,world-ipv4/world-ipv6只展开对应 IP family,none不生成规则,host会展开为当前 VPC gateway LAN IP 的 /32 或 /128,remote-node会展开为当前 VPC 中非本节点 gateway LAN IP 的 /32 或 /128,remote_fqdns会按 desired-statedns_records展开为 /32 或 /128 CIDR;支持 Cilium named port 风格的named_ports,ingress 解析本 endpoint 命名端口,egress remote-group 或 remote_endpoint_selector 解析远端成员命名端口;ICMP 规则支持协议级、icmp_type级和icmp_type+icmp_code级匹配;action=reject会在 policy map/evaluator 中保留 reject verdict 与观测事件。 - Cilium 风格连接状态:stateful allow 规则会建立反向 conntrack 状态,反向流命中会刷新空闲时间;长运行 agent 会按 Cilium CT GC 思路清理 idle state,默认 5 分钟,可用
NETLOOM_CONNTRACK_MAX_IDLE_MS调整;策略变化或 endpoint 删除时也会清理旧状态。 - Cilium 风格策略更新:policy map replace 会先计算 add/update/delete/unchanged diff,成功替换后递增 endpoint policy revision 并记录 audit event;audit event 会包含 previous/current revision、diff stats 和成功/失败结果,失败时记录 attempted revision 与错误但不推进实际 revision;内存 store 具备事务回滚语义。
- Cilium 风格可观测性:policy evaluator 会记录 allow/drop/conntrack/log 统计,为策略拒绝或无匹配 drop 生成 drop event,并为带
log的规则或action=log生成 allow/drop policy event。 - eBPF/TCX ACL datapath:支持节点接口和工作负载 veth 上的 IPv4/IPv6 CIDR+L4/ICMP ACL attach,TCX map 使用 LPM trie 匹配 peer CIDR、TCP/UDP 端口前缀范围以及 ICMP/ICMPv6 type/code 前缀;remote-group 和 remote-endpoint-selector 规则会沿用编译器生成的精确 endpoint CIDR 投影到 TCX fast path,同时 userspace policy map 仍保留 Cilium 风格 remote identity 校验;ICMPv6 使用 next-header 58 编码 type/code;workload fast path 会按 ingress/egress 安全组方向投影到对应 TCX attach 点,agent 自动 attach 会按规则族选择 IPv4、IPv6 或双栈 TCX 程序,双栈场景通过 TCX multi-program anchor 将 IPv6 程序追加到同一接口/方向。
- 周期 reconcile:controller 和 agent 都能从 desired-state JSON 文件周期重读状态,controller 会清理从 desired state 删除的 OVN/内存对象,agent 会持有并按需替换 TCX attachment。
策略边界如下:
PolicyRoute属于 SDN 拓扑意图,由 topology/OVN 路由层处理,支持 reroute/drop 等路由动作;match 支持 source/destination CIDR、protocol、src_ports和dst_ports,OVN 会把多端口范围投影为分组 OR match,Linux datapath 会展开为 source/destination port 组合的 policy rule;reroute 统一使用next_hops表达单跳或 Kube-OVN/OVN 风格的多 next-hop ECMP,OVN backend 会投影到Logical_Router_Policy.nexthops,Linux datapath 会投影为 multipath policy route,本地 resolver 会基于 flow hash 在 next-hop 集合中做稳定选择并保留完整next_hops验证视图;OVN backend 会按 desired state 替换同 priority/match 的 policy,避免 next-hop 或 action 更新后旧策略残留;控制面会拒绝同名策略路由或同一 VPC 内重复 priority/match 的策略路由。RouteTable的静态路由统一使用next_hops表达单跳或 ECMP,默认路由、blackhole、单 next-hop 和 OVN--ecmp多 next-hop 更新都会收敛到当前 desired state,本地 resolver 对静态 ECMP 也按 flow hash 选择稳定 next hop;控制面会拒绝同一 VPC 内重复 destination 的静态路由,避免 OVN logical router 上出现歧义路由。- 控制面会拒绝跨 IP family 的无效意图,包括静态路由 destination/next-hop、SNAT CIDR/external IP、DNAT/Floating IP external/target 以及 LoadBalancer VIP/backend 的 IPv4/IPv6 混配。
- Linux datapath 会把本节点本 VPC 的
PolicyRoute下发为独立 route table 和ip rule/netlink rule,支持 source/destination、TCP/UDPsport/dport、reroute 和 blackhole/drop;默认 netlink 后端会按 desired state 清理托管表范围内的旧 rule 并刷新当前表,NETLOOM_POLICY_ROUTE_TABLE_BASE/NETLOOM_POLICY_ROUTE_TABLE_SIZE可调整表 ID 范围。 SecurityGroupRule属于 ACL 意图,由 eBPF-style policy map 和 TCX ACL datapath 执行。action=reject在 policy map/evaluator 路径会保留为rejectverdict,并生成policy-rejectdrop event;当前 TCX fast path 只能返回 pass/drop,因此可投影的 reject 规则会在 TCX 层按 drop 执行。Endpoint.labels与Endpoint.named_ports可声明 Cilium 风格 endpoint metadata;安全组规则里的remote_endpoint_selector会用 labels 选择同 VPC endpoint,remote_endpoint_expressions补充 Cilium/Kubernetes selector 的In、NotIn、Exists、DoesNotExist表达式,二者同时声明时按 AND 匹配并展开为 endpoint identity 与 /32 或 /128;named_ports会在编译阶段解析成具体 TCP/UDP 端口,ingress 使用被保护 endpoint 的命名端口,egress 支持remote_group或remote_endpoint_selector/remote_endpoint_expressions并按远端成员各自命名端口展开。remote_entities采用 CiliumtoEntities/fromEntities类似语义,支持all、world、world-ipv4、world-ipv6、cluster、private、host、remote-node和none;all会展开为 IPv4/IPv6 默认 CIDR,world表示当前 VPC 子网之外的外部地址集合,world-ipv4/world-ipv6只保留对应 IP family,cluster会展开为当前 VPC 的子网 CIDR,private会展开为 RFC1918 与 ULA CIDR,host会展开为当前 VPC gateway LAN IP 的 /32 或 /128,remote-node会展开为当前 VPC 中非本节点 gateway LAN IP 的 /32 或 /128,none不生成任何策略条目。remote_service采用 CiliumtoServices类似的 egress-only 语义,引用同 VPC 的 desired-stateLoadBalancer,编译时把服务 VIP 展开为 /32 或 /128;LoadBalancer 可用ports声明多个 frontend,规则未显式指定协议或端口时会为每个 frontend 继承对应 protocol/port。remote_cidr可声明except_cidrs,编译器会把主 CIDR 拆成排除例外后的最小 CIDR 集合;和 Cilium 一样,例外 CIDR 必须包含在主 CIDR 内,且不和remote_cidr_group混用。remote_cidr_group采用 CiliumCIDRGroupRef/CIDRSet类似的安全组 CIDR 集合语义,CIDRGroup 作为 desired-state 对象集中维护可复用 CIDR 列表;既支持cidrs简写,也支持entries中为每个 CIDR 声明except_cidrs,编译时会先做 CIDR 差集展开再写入 endpoint policy map。remote_fqdns采用 CiliumtoFQDNs类似的安全组 egress 语义,支持match_name和match_pattern,会从 desired-statedns_records与 agent 的NETLOOM_DNS_OBSERVATIONS_FILE运行时 DNS 观测缓存派生 CIDR policy entry;match_pattern采用 Cilium label wildcard 语义,普通*不跨.,前缀**.可匹配一层或多层子域;dns_records可通过ttl_seconds+observed_at表达 DNS cache TTL,过期记录不会编译进策略。- ACL 不放到 OVN ACL 里实现,避免和 eBPF 策略路径重叠。
- DNAT 和 Floating IP 端口映射会校验协议意图;DNAT external/target 端口相同时投影为 OVN NAT
--portrange,端口不同时直接创建 OVNNAT行并设置external_port_range与logical_port_range,Floating IP (dnat_and_snat) 端口映射也使用同一原生 NAT row 路径,避免为了端口转换引入额外 Load_Balancer 拓扑;分布式 Floating IP 可声明 OVN 原生的logical_port与external_mac,两者必须成对出现在dnat_and_snat规则上;控制面仍把同一个 EIP+端口视为冲突,避免 NAT 投影互相覆盖。 - 控制面 resolver 会解析 DNAT 和 Floating IP (
dnat_and_snat) 入站目标,用于在单元测试和 selftest 中验证 Kube-OVN 风格 NAT 语义。 LoadBalancer使用 OVNlb-add/lr-lb-add/ls-lb-add表达 Kube-OVN 风格的 VPC Service VIP,并统一通过ports声明同一个 Service VIP 下的多个 frontend 和不同 target port;控制面会拒绝同 VPC 内重复的 VIP+协议+端口;支持 OVNaffinity_timeout形式的 ClientIP session affinity,并会投影selection_fields,未显式声明时 session affinity 默认使用 IPv4ip_src或 IPv6ipv6_src;支持 Kube-OVN/OVN 风格的Load_Balancer_Health_Check健康检查选项,多 frontend 会按 VIP 幂等复用并更新对应的 health check row;backend 可声明healthy=false从本地 resolver 与 OVN VIP backend 列表中剔除,未声明时默认健康,控制面要求每个 frontend 至少保留一个健康 backend;state-file controller 可设置NETLOOM_LB_HEALTH_PROBE=1对启用 health check 的 TCP backend 做主动探测,并按success_count/failure_count跨 reconcile 收敛 healthy 状态;同名 LB 的 VIP、backend 和绑定子网变化会按 desired state 收敛,避免旧 Service VIP 残留。- 控制面 resolver 会按 VPC、VIP、协议、端口和绑定子网解析 Service VIP,并基于 flow 与 backend 做稳定选择,用于在单元测试和 selftest 中验证负载均衡语义。
Subnet可以声明provider_network和vlan,OVN 后端会创建localnet逻辑端口,用于对接 Kube-OVN 常见的 underlay/provider network 场景;provider/VLAN 变化或 provider 关闭时会重建或删除 localnet port。Subnet可以开启 DHCP,OVN 后端会为 endpoint logical switch port 生成并绑定 DHCPv4/DHCPv6 options;IPv4 覆盖 router/server/lease/MTU 等常见 Kube-OVN 子网 DHCP 语义,IPv6 会生成server_id并在 router port 上启用dhcpv6_statefulRA;当 DHCP 关闭时会清空端口 DHCP 绑定,保持 desired state 收敛。
- Go
1.26+ task用于执行下面的便捷命令
# 安装开发工具
task deps
# 执行静态检查
task lint
# 执行测试
task test
# 执行跨模块集成测试
task test:integration
# 执行 Docker 多节点 e2e 测试,需要 Docker 和可用的 privileged 容器能力
task test:e2e
# 构建二进制
task buildtask test 会运行所有 Go 包测试,包括 tests/integration;task test:e2e 会启动 Docker Compose lab,用多个容器模拟节点,验证 OVN Northbound、控制面 state-file、OVN desired-state 删除、基于 netlink 的 Linux netns 工作负载、跨节点连通性、策略路由输出、运行时 DNS 观测刷新 FQDN 安全组策略、remote-group 安全组策略、eBPF/TCX ACL drop/allow 和 stale namespace cleanup。
agent 以 NETLOOM_STATE_FILE 运行时可额外设置 NETLOOM_DNS_OBSERVATIONS_FILE=/path/dns.json,让每轮 reconcile 合并运行时 DNS 观测记录并刷新 remote_fqdns 派生策略;文件可以是 {"dns_records":[...]} 文档或 DNSRecord 数组,字段与 desired-state dns_records 相同。
netloom-dns-observer 可作为 DNS proxy/sidecar 前置观测入口使用:它从 base64-lines、hex-lines 或单个 raw DNS wire response 输入中解析 answer/authority/additional 区域的 A/AAAA/CNAME 记录,并原子合并写入同一个 observations 文件,例如 netloom-dns-observer -observations /tmp/netloom-dns.json < responses.b64。
仓库内的 internal/dnsobserver 包提供同一解析能力,便于后续把数据源替换成 eBPF、NFQUEUE 或真实 DNS proxy 捕获路径,而不改变 agent 的策略编译接口。
controller 以 NETLOOM_STATE_FILE 运行时可额外设置 NETLOOM_LB_HEALTH_PROBE=1,对开启 health_check.enabled 的 TCP LoadBalancer backend 做主动 TCP 探测,并在本轮 reconcile 前把失败 backend 标记为 unhealthy;显式 healthy=false 的 backend 视为人工摘除,不会被探测恢复。
controller 使用真实 OVN backend 时会给每次 ovn-nbctl 调用设置默认 30 秒超时,避免 OVN NB 卡住时阻塞 reconcile;可通过 NETLOOM_OVN_NBCTL_TIMEOUT_MS 调整,设置为 0 表示只继承外部 context。
参见 CONTRIBUTING.md。