From 155445ff98637dcb5f51715a7ce6fbbf8c6bbd7b Mon Sep 17 00:00:00 2001
From: Vincentius Raynaldi <vincentius.raynaldi@stud.h-da.de>
Date: Tue, 10 Dec 2024 18:36:57 +0100
Subject: [PATCH] added route subscribe but not yet done

---
 Makefile                                      |  4 ++
 .../networkInstanceHandler.go                 | 32 ++++++++++++++
 .../additions/networkInstances_linux.go       | 44 ++++++++++++++++++-
 .../example01/osclient/additions/types.go     |  1 +
 4 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 1825ed8..aa41e9b 100644
--- a/Makefile
+++ b/Makefile
@@ -42,6 +42,9 @@ generate-yang-models: install-tools
 container: build
 	docker buildx build --rm -t gnmi-target --load -f ./examples/example01/target.Dockerfile .
 
+container-ubuntu: build
+	docker buildx build --rm -t gnmi-target-ubuntu --load -f ./examples/example01/target.Dockerfile --target ubuntu .
+
 container-debug:
 	docker buildx build --rm -t gnmi-target-debug --load -f .examples/example01/Dockerfile.debug .
 
@@ -73,3 +76,4 @@ self-certs:
 clean:
 	$(GOCLEAN)
 	rm -rf $(BUILD_ARTIFACTS_PATH) $(TOOLS_DIR)
+	docker system prune -af
\ No newline at end of file
diff --git a/examples/example01/handlers/network-instances/networkInstanceHandler.go b/examples/example01/handlers/network-instances/networkInstanceHandler.go
index b37b5ea..e5571d7 100644
--- a/examples/example01/handlers/network-instances/networkInstanceHandler.go
+++ b/examples/example01/handlers/network-instances/networkInstanceHandler.go
@@ -54,6 +54,37 @@ func (yh *NetworkInstanceHandler) Init(config *handler.Config, publishToSubsFunc
 		}
 	}
 
+	//subscribe to routing table
+	staticRouteChannel, err := yh.osClient.SubscribeToRoute()
+	if err != nil {
+		return err
+	}
+	go func(){
+		for {
+			select {
+			case update := <- staticRouteChannel:
+				// for _, localInterface := range localInterfaces {
+				// 	staticRoutes, err := yh.osClient.GetStaticRoutes(*localInterface.Name)
+				// 	if err != nil {
+				// 		fmt.Println(err)
+				// 	}
+			
+				// 	for _, staticRoute := range staticRoutes {
+				// 		_, err := yh.updateOrCreateNetworkInstance(staticRoute)
+				// 		if err != nil {
+				// 			fmt.Println(err)
+				// 		}
+				// 	}
+				// }
+
+				_, err := yh.updateOrCreateNetworkInstance(update)
+				if err != nil {
+					fmt.Println(err)
+				}
+			}
+		}
+	}()
+
 	return nil
 }
 
@@ -104,6 +135,7 @@ func (yh *NetworkInstanceHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.
 
 func (yh *NetworkInstanceHandler) updateOrCreateNetworkInstance(localStaticRoute *additions.StaticRoute) ([]*gnmi.Notification, error) {
 	yh.Config.Lock()
+	fmt.Println("received static route: ", localStaticRoute)
 	defer yh.Config.Unlock()
 
 	copyCurrentConfig, err := ygot.DeepCopy(yh.Config.Data)
diff --git a/examples/example01/osclient/additions/networkInstances_linux.go b/examples/example01/osclient/additions/networkInstances_linux.go
index b708e51..b563d9a 100644
--- a/examples/example01/osclient/additions/networkInstances_linux.go
+++ b/examples/example01/osclient/additions/networkInstances_linux.go
@@ -89,6 +89,48 @@ func (oc *networkInstances) GetStaticRoutes(linkName string) ([]*StaticRoute, er
 	return staticRoutes, nil
 }
 
+func (os *networkInstances) SubscribeToRoute() (chan *StaticRoute, error) {
+	// till now, when there is a new notif, it will get all of the network routes table
+	// todo: when get notif, search what has happened (add or update or delete)
+	// todo: only get the network routes table on that specific interfaces(link variable in netlink or code), because there will be more than 1 interfaces
+	// and if we update the all of routing table, it will hurt the performance
+	// todo: if possible change only the specific route either add, update or delete on that specific interface
+	staticRouteChannel := make(chan *StaticRoute)
+	routeChannel := make(chan netlink.RouteUpdate)
+	routeDone:= make(chan struct{})
+	if err := netlink.RouteSubscribe(routeChannel, routeDone); err != nil {
+		return nil, err
+	}
+
+	go func() {
+		for {
+			select {
+			case update := <- routeChannel:
+				log.Printf("received a route update for route: %s", update.Gw.String())
+				// staticRouteChannel <- &StaticRoute{}
+				if update.Route.LinkIndex > 0 {
+					link, err := netlink.LinkByIndex(update.Route.LinkIndex)
+					if err != nil {
+						fmt.Println("error getting link: ", err)
+						continue
+					}
+					if update.Route.Gw != nil && update.Route.Src == nil {
+                        family := nl.FAMILY_V4
+                        if update.Route.Gw.To4() == nil {
+                            family = nl.FAMILY_V6
+                        }
+                        staticRoute := staticRouteBasedOnFamily(link, update.Route, family)
+                        
+                        staticRouteChannel <- staticRoute
+                    }
+				} 
+			}
+		}
+	}()
+
+	return staticRouteChannel, nil
+}
+
 func staticRouteBasedOnFamily(link netlink.Link, route netlink.Route, family int) *StaticRoute {
 	prefix := ipNetIsNilConverter(route.Dst, family)
 	nextHop := &gnmitargetygot.OpenconfigNetworkInstance_NetworkInstances_NetworkInstance_Protocols_Protocol_StaticRoutes_Static_NextHops_NextHop_Config_NextHop_Union_String{String: route.Gw.String()}
@@ -128,4 +170,4 @@ func cidrToIPNet(s string) (*net.IPNet, error) {
 	ipnet.IP = ip
 
 	return ipnet, nil
-}
+}
\ No newline at end of file
diff --git a/examples/example01/osclient/additions/types.go b/examples/example01/osclient/additions/types.go
index f2bcdd2..4bbef24 100644
--- a/examples/example01/osclient/additions/types.go
+++ b/examples/example01/osclient/additions/types.go
@@ -26,4 +26,5 @@ type System interface {
 type NetworkInstances interface {
 	SetStaticRoute(*StaticRoute) error
 	GetStaticRoutes(linkName string) ([]*StaticRoute, error)
+	SubscribeToRoute() (chan *StaticRoute, error)
 }
-- 
GitLab