From f360d46a1ebbd8756473cbd3738cff9b5fb20bb6 Mon Sep 17 00:00:00 2001
From: Trekkie Coder <trekkie@netlox.io>
Date: Mon, 25 Mar 2024 23:16:50 +0900
Subject: [PATCH 1/4] sock-addr: Initial support in loxilb

---
 loxilb-ebpf             |  2 +-
 loxinet/dpbroker.go     | 22 +++++++++++++
 loxinet/dpebpf_linux.go | 73 ++++++++++++++++++++++++++++++++++++++++-
 loxinet/loxinet.go      | 25 +++++++-------
 loxinet/loxinettest.go  |  7 ++--
 loxinet/rules.go        | 12 +++++++
 main.go                 |  7 ++--
 options/options.go      |  5 +--
 8 files changed, 132 insertions(+), 21 deletions(-)

diff --git a/loxilb-ebpf b/loxilb-ebpf
index d144e9657..367c3f71c 160000
--- a/loxilb-ebpf
+++ b/loxilb-ebpf
@@ -1 +1 @@
-Subproject commit d144e9657eb864dd46937fbaa30a5a1d15b4bb43
+Subproject commit 367c3f71c39bad0de60f18d33f8e5da426ed4bf4
diff --git a/loxinet/dpbroker.go b/loxinet/dpbroker.go
index 32e60703b..4732c9846 100644
--- a/loxinet/dpbroker.go
+++ b/loxinet/dpbroker.go
@@ -356,6 +356,15 @@ type UlClDpWorkQ struct {
 	Type   DpTunT
 }
 
+// SockVIPDpWorkQ - work queue entry for local VIP-port rewrite
+type SockVIPDpWorkQ struct {
+	Work   DpWorkT
+	VIP    net.IP
+	Port   uint16
+	RwPort uint16
+	Status *DpStatusT
+}
+
 // DpSyncOpT - Sync Operation type
 type DpSyncOpT uint8
 
@@ -417,6 +426,8 @@ type DpHookInterface interface {
 	DpTableGet(w *TableDpWorkQ) (DpRetT, error)
 	DpCtAdd(w *DpCtInfo) int
 	DpCtDel(w *DpCtInfo) int
+	DpSockVIPAdd(w *SockVIPDpWorkQ) int
+	DpSockVIPDel(w *SockVIPDpWorkQ) int
 	DpTableGC()
 	DpCtGetAsync()
 	DpGetLock()
@@ -723,6 +734,17 @@ func (dp *DpH) DpWorkOnFw(fWq *FwDpWorkQ) DpRetT {
 	return DpWqUnkErr
 }
 
+// DpWorkOnSockVIP - routine to work on local VIP-port rewrite
+func (dp *DpH) DpWorkOnSockVIP(vsWq *SockVIPDpWorkQ) DpRetT {
+	if vsWq.Work == DpCreate {
+		return dp.DpHooks.DpSockVIPAdd(vsWq)
+	} else if vsWq.Work == DpRemove {
+		return dp.DpHooks.DpSockVIPDel(vsWq)
+	}
+
+	return DpWqUnkErr
+}
+
 // DpWorkOnPeerOp - routine to work on a peer request for clustering
 func (dp *DpH) DpWorkOnPeerOp(pWq *PeerDpWorkQ) DpRetT {
 	if pWq.Work == DpCreate {
diff --git a/loxinet/dpebpf_linux.go b/loxinet/dpebpf_linux.go
index 3c01ef677..45dbe8d31 100644
--- a/loxinet/dpebpf_linux.go
+++ b/loxinet/dpebpf_linux.go
@@ -90,6 +90,9 @@ const (
 	EbpfErrFwDel
 	EbpfErrCtAdd
 	EbpfErrCtDel
+	EbpfErrSockVIPMod
+	EbpfErrSockVIPAdd
+	EbpfErrSockVIPDel
 	EbpfErrWqUnk
 )
 
@@ -135,6 +138,8 @@ type (
 	fw4Ent     C.struct_dp_fwv4_ent
 	portAct    C.struct_dp_rdr_act
 	mapNoti    C.struct_ll_dp_map_notif
+	vipKey     C.struct_sock_rwr_key
+	vipAct     C.struct_sock_rwr_action
 )
 
 // DpEbpfH - context container
@@ -256,7 +261,7 @@ func DpEbpfSetLogLevel(logLevel tk.LogLevelT) {
 }
 
 // DpEbpfInit - initialize the ebpf dp subsystem
-func DpEbpfInit(clusterEn bool, nodeNum int, rssEn bool, egrHooks bool, logLevel tk.LogLevelT) *DpEbpfH {
+func DpEbpfInit(clusterEn, rssEn, egrHooks, localVIP bool, nodeNum int, logLevel tk.LogLevelT) *DpEbpfH {
 	var cfg C.struct_ebpfcfg
 
 	if clusterEn {
@@ -269,6 +274,11 @@ func DpEbpfInit(clusterEn bool, nodeNum int, rssEn bool, egrHooks bool, logLevel
 	} else {
 		cfg.egr_hooks = 0
 	}
+	if localVIP {
+		cfg.have_sockrwr = 1
+	} else {
+		cfg.have_sockrwr = 0
+	}
 
 	cfg.nodenum = C.int(nodeNum)
 	cfg.loglevel = 1
@@ -356,6 +366,10 @@ func (e *DpEbpfH) DpEbpfUnInit() {
 		C.free(unsafe.Pointer(ifStr))
 		C.free(unsafe.Pointer(section))
 	}
+
+	if mh.locVIP {
+		C.llb_unload_kern_sock()
+	}
 }
 
 func convNetIP2DPv6Addr(addr unsafe.Pointer, goIP net.IP) {
@@ -1666,6 +1680,63 @@ func (e *DpEbpfH) DpFwRuleDel(w *FwDpWorkQ) int {
 	return e.DpFwRuleMod(w)
 }
 
+// DpSockVIPMod - routine to work on a ebpf local VIP-port rewrite modification
+func (e *DpEbpfH) DpSockVIPMod(w *SockVIPDpWorkQ) int {
+	key := new(vipKey)
+
+	if tk.IsNetIPv6(w.VIP.String()) {
+		return EbpfErrSockVIPMod
+	}
+
+	C.memset(unsafe.Pointer(key), 0, C.sizeof_struct_sock_rwr_key)
+	key.vip[0] = C.uint(tk.IPtonl(w.VIP))
+	key.port = C.ushort(tk.Htons(w.Port))
+
+	if w.Work == DpCreate {
+		dat := new(vipAct)
+		C.memset(unsafe.Pointer(dat), 0, C.sizeof_struct_sock_rwr_action)
+		dat.rw_port = C.ushort(tk.Htons(w.RwPort))
+
+		ret := C.llb_add_map_elem(C.LL_DP_SOCK_RWR_MAP,
+			unsafe.Pointer(key),
+			unsafe.Pointer(dat))
+
+		if ret != 0 {
+			*w.Status = 1
+			return EbpfErrSockVIPAdd
+		}
+
+		*w.Status = 0
+
+	} else if w.Work == DpRemove {
+		C.llb_del_map_elem(C.LL_DP_POL_MAP, unsafe.Pointer(key))
+		return 0
+	}
+	return 0
+}
+
+// DpSockVIPAdd - routine to work on a ebpf local VIP-port rewrite addition
+func (e *DpEbpfH) DpSockVIPAdd(w *SockVIPDpWorkQ) int {
+	ec := e.DpSockVIPMod(w)
+	if ec != 0 {
+		*w.Status = DpCreateErr
+	} else {
+		*w.Status = 0
+	}
+	return ec
+}
+
+// DpSockVIPDel - routine to work on a ebpf local VIP-port rewrite delete
+func (e *DpEbpfH) DpSockVIPDel(w *SockVIPDpWorkQ) int {
+	ec := e.DpSockVIPMod(w)
+	if ec != 0 {
+		*w.Status = DpRemoveErr
+	} else {
+		*w.Status = 0
+	}
+	return ec
+}
+
 //export goMapNotiHandler
 func goMapNotiHandler(m *mapNoti) {
 
diff --git a/loxinet/loxinet.go b/loxinet/loxinet.go
index 014eb634c..55e24c5d4 100644
--- a/loxinet/loxinet.go
+++ b/loxinet/loxinet.go
@@ -19,13 +19,6 @@ package loxinet
 import (
 	"errors"
 	"fmt"
-	apiserver "github.com/loxilb-io/loxilb/api"
-	k8s "github.com/loxilb-io/loxilb/api/k8s"
-	nlp "github.com/loxilb-io/loxilb/api/loxinlp"
-	prometheus "github.com/loxilb-io/loxilb/api/prometheus"
-	cmn "github.com/loxilb-io/loxilb/common"
-	opts "github.com/loxilb-io/loxilb/options"
-	tk "github.com/loxilb-io/loxilib"
 	"net"
 	_ "net/http/pprof"
 	"os"
@@ -36,6 +29,14 @@ import (
 	"sync"
 	"syscall"
 	"time"
+
+	apiserver "github.com/loxilb-io/loxilb/api"
+	k8s "github.com/loxilb-io/loxilb/api/k8s"
+	nlp "github.com/loxilb-io/loxilb/api/loxinlp"
+	prometheus "github.com/loxilb-io/loxilb/api/prometheus"
+	cmn "github.com/loxilb-io/loxilb/common"
+	opts "github.com/loxilb-io/loxilb/options"
+	tk "github.com/loxilb-io/loxilib"
 )
 
 // string constant representing root security zone
@@ -77,6 +78,7 @@ type loxiNetH struct {
 	self   int
 	rssEn  bool
 	eHooks bool
+	locVIP bool
 	pFile  *os.File
 }
 
@@ -209,6 +211,7 @@ func loxiNetInit() {
 	mh.eHooks = opts.Opts.EgrHooks
 	mh.sumDis = opts.Opts.CSumDisable
 	mh.pProbe = opts.Opts.PassiveEPProbe
+	mh.locVIP = opts.Opts.LocalVIP
 	mh.sigCh = make(chan os.Signal, 5)
 	signal.Notify(mh.sigCh, os.Interrupt, syscall.SIGCHLD, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
 
@@ -226,7 +229,7 @@ func loxiNetInit() {
 			return
 		}
 	}
-	if opts.Opts.Rpc == "netrpc" {
+	if opts.Opts.RPC == "netrpc" {
 		rpcMode = RPCTypeNetRPC
 	} else {
 		rpcMode = RPCTypeGRPC
@@ -234,7 +237,7 @@ func loxiNetInit() {
 
 	if !opts.Opts.BgpPeerMode {
 		// Initialize the ebpf datapath subsystem
-		mh.dpEbpf = DpEbpfInit(clusterMode, mh.self, mh.rssEn, mh.eHooks, -1)
+		mh.dpEbpf = DpEbpfInit(clusterMode, mh.rssEn, mh.eHooks, mh.locVIP, mh.self, -1)
 		mh.dp = DpBrokerInit(mh.dpEbpf, rpcMode)
 
 		// Initialize the security zone subsystem
@@ -291,8 +294,8 @@ func loxiNetInit() {
 	}
 
 	// Initialize the k8s subsystem
-	if opts.Opts.K8sApi != "none" {
-		k8s.K8sApiInit(opts.Opts.K8sApi, NetAPIInit(opts.Opts.BgpPeerMode))
+	if opts.Opts.K8sAPI != "none" {
+		k8s.K8sApiInit(opts.Opts.K8sAPI, NetAPIInit(opts.Opts.BgpPeerMode))
 	}
 
 	// Initialize the Prometheus subsystem
diff --git a/loxinet/loxinettest.go b/loxinet/loxinettest.go
index eaea06469..35975e283 100644
--- a/loxinet/loxinettest.go
+++ b/loxinet/loxinettest.go
@@ -18,10 +18,11 @@ package loxinet
 
 import (
 	"fmt"
-	cmn "github.com/loxilb-io/loxilb/common"
-	opts "github.com/loxilb-io/loxilb/options"
 	"net"
 	"testing"
+
+	cmn "github.com/loxilb-io/loxilb/common"
+	opts "github.com/loxilb-io/loxilb/options"
 )
 
 // TestLoxinet - Go unit test entry point
@@ -31,7 +32,7 @@ func TestLoxinet(t *testing.T) {
 	opts.Opts.NoAPI = true
 	opts.Opts.CPUProfile = "none"
 	opts.Opts.Prometheus = false
-	opts.Opts.K8sApi = "none"
+	opts.Opts.K8sAPI = "none"
 	opts.Opts.ClusterNodes = "none"
 
 	fmt.Printf("LoxiLB Net Unit-Test \n")
diff --git a/loxinet/rules.go b/loxinet/rules.go
index 203a2d57e..410d27235 100644
--- a/loxinet/rules.go
+++ b/loxinet/rules.go
@@ -2418,6 +2418,18 @@ func (r *ruleEnt) Nat2DP(work DpWorkT) int {
 
 	mh.dp.ToDpCh <- nWork
 
+	if mh.locVIP {
+		switch at := r.act.action.(type) {
+		case *ruleNatActs:
+			for _, ep := range at.endPoints {
+				nVIPWork := new(SockVIPDpWorkQ)
+				nVIPWork.VIP = nWork.ServiceIP
+				nVIPWork.Port = nWork.L4Port
+				nVIPWork.RwPort = ep.xPort
+				mh.dp.ToDpCh <- nVIPWork
+			}
+		}
+	}
 	return 0
 }
 
diff --git a/main.go b/main.go
index f5a18e042..ad0a8e1d0 100644
--- a/main.go
+++ b/main.go
@@ -18,11 +18,12 @@ package main
 
 import (
 	"fmt"
+	"os"
+	"time"
+
 	"github.com/jessevdk/go-flags"
 	ln "github.com/loxilb-io/loxilb/loxinet"
 	opts "github.com/loxilb-io/loxilb/options"
-	"os"
-	"time"
 )
 
 var version string = "0.9.2-beta"
@@ -43,7 +44,7 @@ func main() {
 		os.Exit(0)
 	}
 
-	go ln.LoxiXsyncMain(opts.Opts.Rpc)
+	go ln.LoxiXsyncMain(opts.Opts.RPC)
 	// Need some time for RPC Handler to be up
 	time.Sleep(2 * time.Second)
 
diff --git a/options/options.go b/options/options.go
index 27f63bd3c..2d664fe5a 100644
--- a/options/options.go
+++ b/options/options.go
@@ -27,8 +27,9 @@ var Opts struct {
 	EgrHooks          bool           `long:"egr-hooks" description:"Enable eBPF egress hooks(experimental)"`
 	BgpPeerMode       bool           `short:"r" long:"peer" description:"Run loxilb with goBGP only, no Datapath"`
 	BlackList         string         `long:"blacklist" description:"Regex string of blacklisted ports" default:"none"`
-	Rpc               string         `long:"rpc" description:"RPC mode for syncing - netrpc or grpc" default:"netrpc"`
-	K8sApi            string         `long:"k8s-api" description:"Enable k8s watcher(experimental)" default:"none"`
+	RPC               string         `long:"rpc" description:"RPC mode for syncing - netrpc or grpc" default:"netrpc"`
+	K8sAPI            string         `long:"k8s-api" description:"Enable k8s watcher(experimental)" default:"none"`
 	IPVSCompat        bool           `long:"ipvs-compat" description:"Enable ipvs-compat(experimental)"`
 	FallBack          bool           `long:"fallback" description:"Fallback to system default networking(experimental)"`
+	LocalVIP          bool           `long:"localvip" description:"support vip availability from lb node(experimental)"`
 }

From 908643b20cbde11f8e2e71653e309944817b1bca Mon Sep 17 00:00:00 2001
From: Trekkie Coder <trekkie@netlox.io>
Date: Mon, 25 Mar 2024 23:30:44 +0900
Subject: [PATCH 2/4] sock-addr: Initial support in loxilb - fixes

---
 loxinet/cluster.go  | 2 +-
 loxinet/dpbroker.go | 4 +++-
 loxinet/rules.go    | 6 +++---
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/loxinet/cluster.go b/loxinet/cluster.go
index 4e5e89113..763365bed 100644
--- a/loxinet/cluster.go
+++ b/loxinet/cluster.go
@@ -245,7 +245,7 @@ func (h *CIStateH) ClusterNodeAdd(node cmn.ClusterNodeMod) (int, error) {
 	cNode := h.NodeMap[node.Addr.String()]
 
 	if cNode != nil {
-		return -1, errors.New("exisitng cnode")
+		return -1, errors.New("existing cnode")
 	}
 
 	cNode = new(ClusterNode)
diff --git a/loxinet/dpbroker.go b/loxinet/dpbroker.go
index 4732c9846..14ffcdb59 100644
--- a/loxinet/dpbroker.go
+++ b/loxinet/dpbroker.go
@@ -502,7 +502,7 @@ func (dp *DpH) DpXsyncRPC(op DpSyncOpT, arg interface{}) int {
 
 	rpcRetries := 0
 	rpcErr := false
-	var cti *DpCtInfo = nil
+	var cti *DpCtInfo
 	var blkCti []DpCtInfo
 
 	switch na := arg.(type) {
@@ -805,6 +805,8 @@ func DpWorkSingle(dp *DpH, m interface{}) DpRetT {
 		ret = dp.DpWorkOnFw(mq)
 	case *PeerDpWorkQ:
 		ret = dp.DpWorkOnPeerOp(mq)
+	case *SockVIPDpWorkQ:
+		ret = dp.DpWorkOnSockVIP(mq)
 	default:
 		tk.LogIt(tk.LogError, "unexpected type %T\n", mq)
 		ret = DpWqUnkErr
diff --git a/loxinet/rules.go b/loxinet/rules.go
index 410d27235..2b1ae7990 100644
--- a/loxinet/rules.go
+++ b/loxinet/rules.go
@@ -1341,7 +1341,7 @@ func (R *RuleH) AddNatLbRule(serv cmn.LbServiceArg, servSecIPs []cmn.LbSecIPArg,
 		// If a NAT rule already exists, we try not reschuffle the order of the end-points.
 		// We will try to append the new end-points at the end, while marking any other end-points
 		// not in the new list as inactive
-		var ruleChg bool = false
+		ruleChg := false
 		eEps := eRule.act.action.(*ruleNatActs).endPoints
 		for i, eEp := range eEps {
 			for j, nEp := range natActs.endPoints {
@@ -1436,7 +1436,7 @@ func (R *RuleH) AddNatLbRule(serv cmn.LbServiceArg, servSecIPs []cmn.LbSecIPArg,
 	r.act.action = &natActs
 	r.ruleNum, err = R.tables[RtLB].Mark.GetCounter()
 	if err != nil {
-		tk.LogIt(tk.LogError, "nat lb-rule - %s:%s hwm error\n", eRule.tuples.String(), eRule.act.String())
+		tk.LogIt(tk.LogError, "nat lb-rule - %s:%s hwm error\n", r.tuples.String(), r.act.String())
 		return RuleAllocErr, errors.New("rule-hwm error")
 	}
 	r.sT = time.Now()
@@ -1682,7 +1682,7 @@ func (R *RuleH) AddFwRule(fwRule cmn.FwRuleArg, fwOptArgs cmn.FwOptArg) (int, er
 	r.act.action = &fwOpts
 	r.ruleNum, err = R.tables[RtFw].Mark.GetCounter()
 	if err != nil {
-		tk.LogIt(tk.LogError, "fw-rule - %s:%s mark error\n", eFw.tuples.String(), eFw.act.String())
+		tk.LogIt(tk.LogError, "fw-rule - %s:%s mark error\n", r.tuples.String(), r.act.String())
 		return RuleAllocErr, errors.New("rule-mark error")
 	}
 	r.sT = time.Now()

From fe7effb5cc5e899195571a79ca442cc530b2c961 Mon Sep 17 00:00:00 2001
From: Trekkie Coder <trekkie@netlox.io>
Date: Tue, 26 Mar 2024 11:35:17 +0900
Subject: [PATCH 3/4] sock-addr: Initial support in loxilb - fixes(2)

---
 loxinet/dpbroker.go     |  4 ++--
 loxinet/dpebpf_linux.go |  6 ++++-
 loxinet/layer3.go       |  2 +-
 loxinet/loxinet.go      |  7 +++++-
 loxinet/rules.go        | 49 +++++++++++++++++++++++++++--------------
 loxinet/utils.go        |  4 ++--
 6 files changed, 49 insertions(+), 23 deletions(-)

diff --git a/loxinet/dpbroker.go b/loxinet/dpbroker.go
index 14ffcdb59..099a35568 100644
--- a/loxinet/dpbroker.go
+++ b/loxinet/dpbroker.go
@@ -490,7 +490,7 @@ func (dp *DpH) WaitXsyncReady(who string) {
 
 // DpXsyncRPC - Routine for syncing connection information with peers
 func (dp *DpH) DpXsyncRPC(op DpSyncOpT, arg interface{}) int {
-	var reply, ret int
+	var ret int
 	var err error
 
 	dp.SyncMtx.Lock()
@@ -523,7 +523,7 @@ func (dp *DpH) DpXsyncRPC(op DpSyncOpT, arg interface{}) int {
 			}
 		}
 
-		reply = 0
+		reply := 0
 		rpcCallStr := ""
 		if op == DpSyncAdd || op == DpSyncBcast {
 			if len(blkCti) > 0 {
diff --git a/loxinet/dpebpf_linux.go b/loxinet/dpebpf_linux.go
index 45dbe8d31..6641961b9 100644
--- a/loxinet/dpebpf_linux.go
+++ b/loxinet/dpebpf_linux.go
@@ -1703,13 +1703,17 @@ func (e *DpEbpfH) DpSockVIPMod(w *SockVIPDpWorkQ) int {
 
 		if ret != 0 {
 			*w.Status = 1
+			tk.LogIt(tk.LogError, "sock-vip rwr add failed\n")
 			return EbpfErrSockVIPAdd
 		}
 
+		tk.LogIt(tk.LogDebug, "sock-vip (%s:%v) rwr (%v) added\n",
+			w.VIP.String(), w.Port, w.RwPort)
+
 		*w.Status = 0
 
 	} else if w.Work == DpRemove {
-		C.llb_del_map_elem(C.LL_DP_POL_MAP, unsafe.Pointer(key))
+		C.llb_del_map_elem(C.LL_DP_SOCK_RWR_MAP, unsafe.Pointer(key))
 		return 0
 	}
 	return 0
diff --git a/loxinet/layer3.go b/loxinet/layer3.go
index 27aae5ec3..e6750bab3 100644
--- a/loxinet/layer3.go
+++ b/loxinet/layer3.go
@@ -182,7 +182,7 @@ func (l3 *L3H) IfaAdd(Obj string, Cidr string) (int, error) {
 // IfaDelete - Deletes an interface IP address (primary or secondary) and de-associate from Obj
 // Obj can be anything but usually it is the name of a valid interface
 func (l3 *L3H) IfaDelete(Obj string, Cidr string) (int, error) {
-	var found bool = false
+	found := false
 	addr, network, err := net.ParseCIDR(Cidr)
 	if err != nil {
 		tk.LogIt(tk.LogError, "ifa delete - malformed %s:%s\n", Cidr, Obj)
diff --git a/loxinet/loxinet.go b/loxinet/loxinet.go
index 55e24c5d4..8bdea558e 100644
--- a/loxinet/loxinet.go
+++ b/loxinet/loxinet.go
@@ -20,7 +20,6 @@ import (
 	"errors"
 	"fmt"
 	"net"
-	_ "net/http/pprof"
 	"os"
 	"os/signal"
 	"runtime/debug"
@@ -57,6 +56,8 @@ const (
 	BpfFsCheckFile = "/opt/loxilb/dp/bpf/intf_map"
 	ARPAcceptAll   = "sysctl net.ipv4.conf.all.arp_accept=1"
 	ARPAcceptDfl   = "sysctl net.ipv4.conf.default.arp_accept=1"
+	UnMountCG2     = "umount /sys/fs/cgroup/unified || mkdir -p /sys/fs/cgroup/unified"
+	MountCG2       = "mount -t cgroup2 -o rw,relatime,nsdelegate,memory_recursiveprot cgroup2 /sys/fs/cgroup/unified"
 )
 
 type loxiNetH struct {
@@ -236,6 +237,10 @@ func loxiNetInit() {
 	}
 
 	if !opts.Opts.BgpPeerMode {
+		if mh.locVIP {
+			RunCommand(UnMountCG2, false)
+			RunCommand(MountCG2, false)
+		}
 		// Initialize the ebpf datapath subsystem
 		mh.dpEbpf = DpEbpfInit(clusterMode, mh.rssEn, mh.eHooks, mh.locVIP, mh.self, -1)
 		mh.dp = DpBrokerInit(mh.dpEbpf, rpcMode)
diff --git a/loxinet/rules.go b/loxinet/rules.go
index 2b1ae7990..f906c125a 100644
--- a/loxinet/rules.go
+++ b/loxinet/rules.go
@@ -23,8 +23,8 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"net"
+	"os"
 	"reflect"
 	"sort"
 	"strconv"
@@ -362,7 +362,7 @@ func RulesInit(zone *Zone) *RuleH {
 	// Check if there exist a common CA certificate
 	if exists := FileExists(rootCACertile); exists {
 
-		rootCA, err := ioutil.ReadFile(rootCACertile)
+		rootCA, err := os.ReadFile(rootCACertile)
 		if err != nil {
 			tk.LogIt(tk.LogError, "RootCA cert load failed : %v\n", err)
 		} else {
@@ -1864,10 +1864,10 @@ func (R *RuleH) AddEPHost(apiCall bool, hostName string, name string, args epHos
 	}
 	// Load CA cert into pool
 	if args.probeType == HostProbeHTTPS {
-		// Check if there exist a CA certificate particularily for this EP
+		// Check if there exist a CA certificate particularly for this EP
 		rootCACertile := cmn.CertPath + hostName + "/" + cmn.CACertFileName
 		if exists := FileExists(rootCACertile); exists {
-			rootCA, err := ioutil.ReadFile(rootCACertile)
+			rootCA, err := os.ReadFile(rootCACertile)
 			if err != nil {
 				tk.LogIt(tk.LogError, "RootCA cert load failed : %v", err)
 				return RuleArgsErr, errors.New("rootca cert load failed")
@@ -2266,6 +2266,33 @@ func (R *RuleH) RuleDestructAll() {
 	return
 }
 
+// VIP2DP - Sync state of nat-rule for local sock VIP-port rewrite
+func (r *ruleEnt) VIP2DP(work DpWorkT) int {
+	portMap := make(map[int]struct{})
+	if mh.locVIP {
+		switch at := r.act.action.(type) {
+		case *ruleNatActs:
+			for _, ep := range at.endPoints {
+				if _, ok := portMap[int(ep.xPort)]; ok {
+					continue
+				}
+				portMap[int(ep.xPort)] = struct{}{}
+				nVIPWork := new(SockVIPDpWorkQ)
+				nVIPWork.Work = work
+				if ep.inActive {
+					nVIPWork.Work = DpRemove
+				}
+				nVIPWork.VIP = r.tuples.l3Dst.addr.IP.Mask(r.tuples.l3Dst.addr.Mask)
+				nVIPWork.Port = r.tuples.l4Dst.val
+				nVIPWork.RwPort = ep.xPort
+				nVIPWork.Status = new(DpStatusT)
+				mh.dp.ToDpCh <- nVIPWork
+			}
+		}
+	}
+	return 0
+}
+
 // Nat2DP - Sync state of nat-rule entity to data-path
 func (r *ruleEnt) Nat2DP(work DpWorkT) int {
 
@@ -2418,18 +2445,8 @@ func (r *ruleEnt) Nat2DP(work DpWorkT) int {
 
 	mh.dp.ToDpCh <- nWork
 
-	if mh.locVIP {
-		switch at := r.act.action.(type) {
-		case *ruleNatActs:
-			for _, ep := range at.endPoints {
-				nVIPWork := new(SockVIPDpWorkQ)
-				nVIPWork.VIP = nWork.ServiceIP
-				nVIPWork.Port = nWork.L4Port
-				nVIPWork.RwPort = ep.xPort
-				mh.dp.ToDpCh <- nVIPWork
-			}
-		}
-	}
+	r.VIP2DP(nWork.Work)
+
 	return 0
 }
 
diff --git a/loxinet/utils.go b/loxinet/utils.go
index dac770bef..03170cbbe 100644
--- a/loxinet/utils.go
+++ b/loxinet/utils.go
@@ -250,7 +250,7 @@ func IsIPHostNetAddr(ip net.IP) bool {
 	return false
 }
 
-// GratArpReq - sends a gratuitious arp reply given the DIP, SIP and interface name
+// GratArpReq - sends a gratuitous arp reply given the DIP, SIP and interface name
 func GratArpReq(AdvIP net.IP, ifName string) (int, error) {
 	bcAddr := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
 	fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, int(tk.Htons(syscall.ETH_P_ARP)))
@@ -311,7 +311,7 @@ func GratArpReq(AdvIP net.IP, ifName string) (int, error) {
 	return 0, nil
 }
 
-// GratArpReq - sends a gratuitious arp reply given the DIP, SIP and interface name
+// GratArpReq - sends a gratuitous arp reply given the DIP, SIP and interface name
 func GratArpReqWithCtx(ctx context.Context, rCh chan<- int, AdvIP net.IP, ifName string) (int, error) {
 	for {
 		select {

From 3500b7893121f16906dae92506fc166969e27bb2 Mon Sep 17 00:00:00 2001
From: Trekkie Coder <trekkie@netlox.io>
Date: Tue, 26 Mar 2024 11:39:36 +0900
Subject: [PATCH 4/4] sock-addr: Initial support in loxilb - Makefile changes

---
 Makefile    | 2 ++
 loxilb-ebpf | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 60cc940db..d1b96d4d5 100644
--- a/Makefile
+++ b/Makefile
@@ -30,6 +30,7 @@ docker-cp: build
 	docker cp /opt/loxilb/llb_ebpf_main.o $(loxilbid):/opt/loxilb/llb_ebpf_main.o
 	docker cp /opt/loxilb/llb_ebpf_emain.o $(loxilbid):/opt/loxilb/llb_ebpf_emain.o
 	docker cp /opt/loxilb/llb_xdp_main.o $(loxilbid):/opt/loxilb/llb_xdp_main.o
+	docker cp /opt/loxilb/llb_kern_sock.o $(loxilbid):/opt/loxilb/llb_kern_sock.o
 	docker cp loxilb-ebpf/kernel/loxilb_dp_debug  $(loxilbid):/usr/local/sbin/
 	docker cp loxilb-ebpf/libbpf/src/libbpf.so.0.8.1 $(loxilbid):/usr/lib64/
 	docker cp loxilb-ebpf/utils/loxilb_dp_tool $(loxilbid):/usr/local/sbin/
@@ -38,6 +39,7 @@ docker-cp-ebpf: build
 	docker cp /opt/loxilb/llb_ebpf_main.o $(loxilbid):/opt/loxilb/llb_ebpf_main.o
 	docker cp /opt/loxilb/llb_ebpf_emain.o $(loxilbid):/opt/loxilb/llb_ebpf_emain.o
 	docker cp /opt/loxilb/llb_xdp_main.o $(loxilbid):/opt/loxilb/llb_xdp_main.o
+	docker cp /opt/loxilb/llb_kern_sock.o $(loxilbid):/opt/loxilb/llb_kern_sock.o
 	docker cp loxilb-ebpf/kernel/loxilb_dp_debug  $(loxilbid):/usr/local/sbin/
 	docker cp loxilb-ebpf/libbpf/src/libbpf.so.0.8.1 $(loxilbid):/usr/lib64/
 
diff --git a/loxilb-ebpf b/loxilb-ebpf
index 367c3f71c..2f8f97336 160000
--- a/loxilb-ebpf
+++ b/loxilb-ebpf
@@ -1 +1 @@
-Subproject commit 367c3f71c39bad0de60f18d33f8e5da426ed4bf4
+Subproject commit 2f8f973361bc4e06b6c00fe3b913e5633594a95a