Skip to content
Snippets Groups Projects
interfaces_linux.go 5.47 KiB
Newer Older
  • Learn to ignore specific revisions
  • Shrey Garg's avatar
    Shrey Garg committed
    package additions
    
    import (
    	"net"
    
    
    	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
    
    Shrey Garg's avatar
    Shrey Garg committed
    	"github.com/openconfig/ygot/ygot"
    	log "github.com/sirupsen/logrus"
    	"github.com/vishvananda/netlink"
    )
    
    func (oc *interfaces) GetInterfaces() ([]*Interface, error) {
    	// Create Interfaces
    	h, err := netlink.NewHandle()
    	if err != nil {
    		log.WithFields(log.Fields{}).Error(err)
    	}
    
    	localIfaces, err := h.LinkList()
    	if err != nil {
    		log.WithFields(log.Fields{}).Error(err)
    	}
    
    	interfaces := make([]*Interface, len(localIfaces))
    	for i, localIface := range localIfaces {
    		intf, err := interfaceFromLink(localIface)
    		if err != nil {
    			return nil, err
    		}
    		interfaces[i] = intf
    	}
    	return interfaces, nil
    }
    
    func (oc *interfaces) SetInterface(interfaceToSet *Interface) error {
    	link, err := netlink.LinkByName(*interfaceToSet.Name)
    	if err != nil {
    		_, ok := err.(netlink.LinkNotFoundError)
    		if !ok {
    			return err
    		}
    		link = &netlink.Dummy{
    			LinkAttrs: netlink.LinkAttrs{
    				Flags: net.FlagUp,
    				Name:  *interfaceToSet.Name,
    			},
    		}
    	}
    
    
    	log.Debug("Current Interface-Name: ", link.Attrs().Name)
    
    
    	if *interfaceToSet.Enabled {
    		netlink.LinkSetUp(link)
    	} else {
    		netlink.LinkSetDown(link)
    	}
    
    
    Shrey Garg's avatar
    Shrey Garg committed
    	//TODO: add more set options for interface
    	if err := netlink.LinkSetMTU(link, int(*interfaceToSet.MTU)); err != nil {
    
    		log.Debugf("Failed to set MTU: %d ; err: %v", *interfaceToSet.MTU, err)
    
    Shrey Garg's avatar
    Shrey Garg committed
    		return err
    	}
    
    	for _, ipv4Address := range interfaceToSet.Ipv4Addresses {
    		if err := netlink.AddrReplace(link, &netlink.Addr{
    			IPNet: &ipv4Address.IPNet,
    		}); err != nil {
    
    			log.Debug("Failed to set ipv4 with ip-net: ", ipv4Address.IPNet.String())
    
    Shrey Garg's avatar
    Shrey Garg committed
    			return err
    		}
    	}
    
    	for _, ipv6Address := range interfaceToSet.Ipv6Addresses {
    		if err := netlink.AddrReplace(link, &netlink.Addr{
    			IPNet: &ipv6Address.IPNet,
    		}); err != nil {
    
    			log.Debug("Failed to set ipv6 with ip-net: ", ipv6Address.IPNet.String())
    
    Shrey Garg's avatar
    Shrey Garg committed
    			return err
    		}
    	}
    
    	return nil
    }
    
    func (oc *interfaces) SubscribeToInterfaces() (chan *Interface, error) {
    	interfaceChannel := make(chan *Interface)
    	linkChannel := make(chan netlink.LinkUpdate)
    	linkDone := make(chan struct{})
    	if err := netlink.LinkSubscribe(linkChannel, linkDone); err != nil {
    		return nil, err
    	}
    
    	// receive updates from all links; triggers an update of the config
    	go func() {
    		for {
    			select {
    			case update := <-linkChannel:
    				log.Println("received a link update for link: ", update.Link.Attrs().Name)
    				//TODO: error handling
    				interfaceUpdate, _ := interfaceFromLink(update.Link)
    				interfaceChannel <- interfaceUpdate
    			}
    		}
    	}()
    
    	return interfaceChannel, nil
    }
    
    func interfaceFromLink(localIface netlink.Link) (*Interface, error) {
    	adminStatus := gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UNSET
    	loopbackMode := ygot.Bool(false)
    
    	attributes := localIface.Attrs()
    
    	if attributes.Flags&net.FlagUp != 0 {
    		adminStatus = gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UP
    	}
    
    	if attributes.Flags&net.FlagLoopback != 0 {
    		loopbackMode = ygot.Bool(true)
    	}
    
    	ipv4Addresses, err := netlink.AddrList(localIface, netlink.FAMILY_V4)
    	if err != nil {
    		return nil, err
    	}
    
    	ipv6Addresses, err := netlink.AddrList(localIface, netlink.FAMILY_V6)
    	if err != nil {
    		return nil, err
    	}
    
    	IPv4Addresses := make([]IPAddress, len(ipv4Addresses))
    	for i, addr := range ipv4Addresses {
    		IPv4Addresses[i] = IPAddress{
    			IPNet:     *addr.IPNet,
    			Broadcast: addr.Broadcast,
    		}
    	}
    
    	IPv6Addresses := make([]IPAddress, len(ipv6Addresses))
    	for i, addr := range ipv6Addresses {
    		IPv6Addresses[i] = IPAddress{
    			IPNet:     *addr.IPNet,
    			Broadcast: addr.Broadcast,
    		}
    	}
    
    	return &Interface{
    		Index:         ygot.Uint32(uint32(attributes.Index)),
    		Name:          ygot.String(attributes.Name),
    		Type:          gnmitargetygot.IETFInterfaces_InterfaceType_UNSET,
    		MTU:           ygot.Uint16(uint16(attributes.MTU)),
    		AdminStatus:   adminStatus,
    		LoopbackMode:  loopbackMode,
    		OperState:     setOperState(attributes.OperState),
    
    		Enabled:       ygot.Bool(setConfigEnabled(attributes.OperState)),
    
    Shrey Garg's avatar
    Shrey Garg committed
    		Ipv4Addresses: IPv4Addresses,
    		Ipv6Addresses: IPv6Addresses,
    	}, nil
    }
    
    // setOperState helper function that allows to return the correct OperStatus
    // type for openconfig interfaces based on a netlink LinkOperState
    func setOperState(state netlink.LinkOperState) gnmitargetygot.E_OpenconfigInterfaces_Interfaces_Interface_State_OperStatus {
    	switch state {
    	case netlink.OperUp:
    		return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UP
    	case netlink.OperDown:
    		return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_DOWN
    	case netlink.OperDormant:
    		return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_DORMANT
    	case netlink.OperTesting:
    		return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_TESTING
    	case netlink.OperNotPresent:
    		return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_NOT_PRESENT
    	case netlink.OperLowerLayerDown:
    		return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_LOWER_LAYER_DOWN
    	default:
    		return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UNKNOWN
    	}
    }
    
    
    // setOperState helper function that allows to return the correct OperStatus
    // type for openconfig interfaces based on a netlink LinkOperState
    func setConfigEnabled(state netlink.LinkOperState) bool {
    	switch state {
    	case netlink.OperUp:
    		return true
    	default:
    		return false
    	}
    }