Skip to content
Snippets Groups Projects
interfacesHandler.go 6.64 KiB
Newer Older
  • Learn to ignore specific revisions
  • package interfaces
    
    import (
    	"fmt"
    	"net"
    
    	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
    	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient"
    	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient/additions"
    
    	"code.fbi.h-da.de/danet/gnmi-target/handler"
    
    	"github.com/openconfig/gnmi/proto/gnmi"
    	"github.com/openconfig/ygot/ygot"
    	log "github.com/sirupsen/logrus"
    )
    
    // InterfacesHandler is the implementation of a gnmitarget.PathHandler.
    type InterfacesHandler struct {
    
    	osClient osclient.Osclient
    }
    
    func NewInterfacesHandler() *InterfacesHandler {
    	return &InterfacesHandler{
    
    		DefaultPathHandler: handler.DefaultPathHandler{
    			Name: "openconfig-interfaces-handler",
    			Paths: map[string]struct{}{
    				"/interfaces": {},
    			},
    
    func (yh *InterfacesHandler) Init(config *handler.Config, publishToSubsFunc func([]*gnmi.Notification) error) error {
    	yh.Config = config
    	yh.PublishToSubs = publishToSubsFunc
    
    
    	// needed for interfaces and network instances
    	localInterfaces, err := yh.osClient.GetInterfaces()
    	if err != nil {
    		return err
    	}
    
    	for _, localInterface := range localInterfaces {
    
    		_, err := yh.updateOrCreateInterface(localInterface)
    		if err != nil {
    
    			return err
    		}
    	}
    
    	// subscribe to interfaces
    	interfaceChannel, err := yh.osClient.SubscribeToInterfaces()
    	if err != nil {
    		return err
    	}
    	go func() {
    		for {
    			select {
    			case update := <-interfaceChannel:
    
    				//lock access for model
    				diff, err := yh.updateOrCreateInterface(update)
    				if err != nil {
    					log.Errorf("Error within interface subscription goroutine; %v", err)
    					// TODO: check again
    					break
    				}
    				if err := yh.PublishToSubs(diff); err != nil {
    					log.Errorf("Error within interface subscription goroutine; %v", err)
    
    				}
    			}
    		}
    	}()
    
    	return nil
    }
    
    func (yh *InterfacesHandler) Update(c ygot.ValidatedGoStruct, updates []*gnmi.Update) error {
    
    	fmt.Println("Update request received for ", yh.GetName())
    
    	config, ok := c.(*gnmitargetygot.Gnmitarget)
    	if !ok {
    		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
    	}
    
    	interfaces := config.GetInterfaces()
    
    	if interfaces != nil {
    		if intfMap := interfaces.Interface; intfMap != nil {
    			for _, intf := range intfMap {
    				osInterface := &additions.Interface{}
    				osInterface.Ipv4Addresses = make([]additions.IPAddress, 0)
    				osInterface.Ipv6Addresses = make([]additions.IPAddress, 0)
    
    				if state := intf.GetState(); state != nil {
    					osInterface.Index = state.Ifindex
    					osInterface.OperState = state.OperStatus
    					osInterface.AdminStatus = state.AdminStatus
    					osInterface.LoopbackMode = state.LoopbackMode
    				}
    
    				if config := intf.GetConfig(); config != nil {
    					osInterface.Name = config.Name
    					osInterface.Type = config.Type
    					osInterface.MTU = config.Mtu
    				}
    
    				if *osInterface.Name != "lo" && *osInterface.Name != "wlan0" {
    					if subinterfaces := intf.Subinterfaces; subinterfaces != nil {
    						if subintfMap := subinterfaces.Subinterface; subintfMap != nil {
    							for _, subintf := range subintfMap {
    								if ipv4s := subintf.GetIpv4(); ipv4s != nil {
    									for _, addr := range subintf.Ipv4.Addresses.Address {
    										if addr.Ip != nil && addr.Config.PrefixLength != nil {
    											osInterface.Ipv4Addresses = append(osInterface.Ipv4Addresses, additions.IPAddress{
    												IPNet: net.IPNet{
    													IP:   net.ParseIP(addr.GetIp()),
    													Mask: net.CIDRMask(int(addr.GetConfig().GetPrefixLength()), 32),
    												},
    											})
    										}
    									}
    								}
    
    								if ipv6s := subintf.GetIpv6(); ipv6s != nil {
    									for _, addr := range subintf.Ipv6.Addresses.Address {
    										if addr.Ip != nil && addr.Config.PrefixLength != nil {
    											osInterface.Ipv6Addresses = append(osInterface.Ipv6Addresses, additions.IPAddress{
    												IPNet: net.IPNet{
    													IP:   net.ParseIP(addr.GetIp()),
    													Mask: net.CIDRMask(int(addr.GetConfig().GetPrefixLength()), 32),
    												},
    											})
    										}
    									}
    								}
    							}
    						}
    					}
    					if err := yh.osClient.SetInterface(osInterface); err != nil {
    						log.Debug("Failed to set interface: ", err)
    						return err
    					}
    				}
    			}
    		}
    	}
    
    	return nil
    }
    
    
    func (yh *InterfacesHandler) updateOrCreateInterface(localInterface *additions.Interface) ([]*gnmi.Notification, error) {
    	yh.Config.Lock()
    	defer yh.Config.Unlock()
    
    	copyCurrentConfig, err := ygot.DeepCopy(yh.Config.Data)
    	if err != nil {
    		return nil, err
    	}
    
    	newConfig, ok := copyCurrentConfig.(*gnmitargetygot.Gnmitarget)
    	if !ok {
    		return nil, fmt.Errorf("Wrong type, exptected: %T, got: %T", (*gnmitargetygot.OpenconfigInterfaces_Interfaces)(nil), copyCurrentConfig)
    	}
    
    	confInterfaces := newConfig.GetOrCreateInterfaces()
    
    
    	iface := confInterfaces.GetOrCreateInterface(*localInterface.Name)
    	state := iface.GetOrCreateState()
    	config := iface.GetOrCreateConfig()
    
    	state.Ifindex = localInterface.Index
    	iface.Name = localInterface.Name
    
    	//base ethernet interface type would be 6 (see iana-if-type.yang)
    	config.Type = localInterface.Type
    	config.Mtu = localInterface.MTU
    	config.Name = localInterface.Name
    
    	state.OperStatus = localInterface.OperState
    	state.AdminStatus = localInterface.AdminStatus
    	state.LoopbackMode = localInterface.LoopbackMode
    
    	for i, addr := range localInterface.Ipv4Addresses {
    		subiface := iface.GetOrCreateSubinterfaces().GetOrCreateSubinterface(uint32(i))
    		subifaceConfig := subiface.GetOrCreateConfig()
    		subifaceConfig.Index = ygot.Uint32(uint32(i))
    
    		ipv4 := subiface.GetOrCreateIpv4()
    		ipv4Addr := ipv4.GetOrCreateAddresses().GetOrCreateAddress(addr.IP.String())
    		ipv4AddrConf := ipv4Addr.GetOrCreateConfig()
    		ipv4AddrConf.Ip = ygot.String(addr.IP.String())
    
    		prefix, _ := addr.IPNet.Mask.Size()
    		convPrefix := uint8(prefix)
    		ipv4AddrConf.PrefixLength = &convPrefix
    	}
    
    	for i, addr := range localInterface.Ipv6Addresses {
    		subiface := iface.GetOrCreateSubinterfaces().GetOrCreateSubinterface(uint32(i))
    
    		subifaceConfig := subiface.GetOrCreateConfig()
    		subifaceConfig.Index = ygot.Uint32(uint32(i))
    
    
    		ipv6 := subiface.GetOrCreateIpv6()
    		ipv6Addr := ipv6.GetOrCreateAddresses().GetOrCreateAddress(addr.IP.String())
    		ipv6AddrConf := ipv6Addr.GetOrCreateConfig()
    		ipv6AddrConf.Ip = ygot.String(addr.IP.String())
    
    		prefix, _ := addr.IPNet.Mask.Size()
    		convPrefix := uint8(prefix)
    		ipv6AddrConf.PrefixLength = &convPrefix
    	}
    
    	//validate struct
    
    	if err := newConfig.Validate(); err != nil {
    		return nil, err
    
    	notifications, err := ygot.DiffWithAtomic(yh.Config.Data, newConfig)
    	if err != nil {
    		return nil, err
    	}
    
    	yh.Config.Data = newConfig
    
    	return notifications, nil