Files
inp2p/internal/server/sdwan_api.go
openclaw 489c2d191c feat: raw binary SDWAN data plane + EncodeRaw + TUN close-on-stop
- protocol: add SubTunnelSDWANRaw subtype + EncodeRaw() for zero-copy IP packets
- client: tunReadLoop sends raw frames (no JSON/base64 overhead)
- client: SubTunnelSDWANRaw handler strips header and writes directly to TUN
- client: Stop() closes TUN file FIRST to unblock tunReadLoop
- server: SubTunnelSDWANRaw handler parses IPv4 src/dst from raw packet
- server: RouteSDWANPacket forwards as raw frame to destination

Verified: hcss(10.10.0.3) ↔ i-6986(10.10.0.2) ping 3/3, 0% loss, 46ms RTT
2026-03-02 18:22:41 +08:00

149 lines
2.9 KiB
Go

package server
import (
"net/netip"
"github.com/openp2p-cn/inp2p/pkg/protocol"
)
func (s *Server) GetSDWAN() protocol.SDWANConfig {
return s.sdwan.get()
}
func (s *Server) SetSDWAN(cfg protocol.SDWANConfig) error {
if err := s.sdwan.save(cfg); err != nil {
return err
}
s.broadcastSDWAN(s.sdwan.get())
return nil
}
func (s *Server) broadcastSDWAN(cfg protocol.SDWANConfig) {
if !cfg.Enabled || cfg.GatewayCIDR == "" {
return
}
s.mu.RLock()
defer s.mu.RUnlock()
for _, n := range s.nodes {
if !n.IsOnline() {
continue
}
_ = n.Conn.Write(protocol.MsgPush, protocol.SubPushSDWANConfig, cfg)
}
}
func (s *Server) pushSDWANPeer(to *NodeInfo, peer protocol.SDWANPeer) {
if to == nil || !to.IsOnline() {
return
}
_ = to.Conn.Write(protocol.MsgPush, protocol.SubPushSDWANPeer, peer)
}
func (s *Server) pushSDWANDel(to *NodeInfo, peer protocol.SDWANPeer) {
if to == nil || !to.IsOnline() {
return
}
_ = to.Conn.Write(protocol.MsgPush, protocol.SubPushSDWANDel, peer)
}
func (s *Server) announceSDWANNodeOnline(nodeName string) {
cfg := s.sdwan.get()
if cfg.GatewayCIDR == "" {
return
}
selfIP := ""
for _, n := range cfg.Nodes {
if n.Node == nodeName {
selfIP = n.IP
break
}
}
if selfIP == "" {
return
}
s.mu.RLock()
newNode := s.nodes[nodeName]
if newNode == nil || !newNode.IsOnline() {
s.mu.RUnlock()
return
}
for _, n := range cfg.Nodes {
if n.Node == nodeName {
continue
}
other := s.nodes[n.Node]
if other == nil || !other.IsOnline() {
continue
}
// existing -> new
s.pushSDWANPeer(newNode, protocol.SDWANPeer{Node: n.Node, IP: n.IP, Online: true})
// new -> existing
s.pushSDWANPeer(other, protocol.SDWANPeer{Node: nodeName, IP: selfIP, Online: true})
}
s.mu.RUnlock()
}
func (s *Server) announceSDWANNodeOffline(nodeName string) {
cfg := s.sdwan.get()
if cfg.GatewayCIDR == "" {
return
}
selfIP := ""
for _, n := range cfg.Nodes {
if n.Node == nodeName {
selfIP = n.IP
break
}
}
s.mu.RLock()
defer s.mu.RUnlock()
for _, n := range s.nodes {
if n.Name == nodeName || !n.IsOnline() {
continue
}
s.pushSDWANDel(n, protocol.SDWANPeer{Node: nodeName, IP: selfIP, Online: false})
}
}
func (s *Server) RouteSDWANPacket(from *NodeInfo, pkt protocol.SDWANPacket) {
if from == nil {
return
}
cfg := s.sdwan.get()
if cfg.GatewayCIDR == "" || pkt.DstIP == "" || len(pkt.Payload) == 0 {
return
}
dst, err := netip.ParseAddr(pkt.DstIP)
if err != nil {
return
}
toNode := ""
for _, n := range cfg.Nodes {
if n.IP == pkt.DstIP {
toNode = n.Node
break
}
if p, err := netip.ParseAddr(n.IP); err == nil && p == dst {
toNode = n.Node
break
}
}
if toNode == "" || toNode == from.Name {
return
}
s.mu.RLock()
to := s.nodes[toNode]
s.mu.RUnlock()
if to == nil || !to.IsOnline() {
return
}
pkt.FromNode = from.Name
pkt.ToNode = toNode
frame := protocol.EncodeRaw(protocol.MsgTunnel, protocol.SubTunnelSDWANRaw, pkt.Payload)
_ = to.Conn.WriteRaw(frame)
}