go.ligato.io/vpp-agent/v3@v3.5.0/plugins/linux/ifplugin/ifplugin.go (about)

     1  // Copyright (c) 2018 Cisco and/or its affiliates.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at:
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //go:generate descriptor-adapter --descriptor-name Interface  --value-type *linux_interfaces.Interface --meta-type *ifaceidx.LinuxIfMetadata --import "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces" --import "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/ifaceidx" --output-dir "descriptor"
    16  //go:generate descriptor-adapter --descriptor-name InterfaceVrf  --value-type *linux_interfaces.Interface --import "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces" --output-dir "descriptor"
    17  //go:generate descriptor-adapter --descriptor-name InterfaceAddress  --value-type *linux_interfaces.Interface --import "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces" --output-dir "descriptor"
    18  
    19  package ifplugin
    20  
    21  import (
    22  	"github.com/pkg/errors"
    23  
    24  	"go.ligato.io/cn-infra/v2/infra"
    25  	"go.ligato.io/cn-infra/v2/servicelabel"
    26  
    27  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    28  	"go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/descriptor"
    29  	"go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/ifaceidx"
    30  	"go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/linuxcalls"
    31  	"go.ligato.io/vpp-agent/v3/plugins/linux/nsplugin"
    32  	"go.ligato.io/vpp-agent/v3/plugins/netalloc"
    33  	"go.ligato.io/vpp-agent/v3/proto/ligato/linux"
    34  	linux_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces"
    35  )
    36  
    37  const (
    38  	// by default, at most 10 go routines will split the configured namespaces
    39  	// to execute the Retrieve operation in parallel.
    40  	defaultGoRoutinesCnt = 10
    41  )
    42  
    43  // IfPlugin configures Linux VETH and TAP interfaces using Netlink API.
    44  type IfPlugin struct {
    45  	Deps
    46  
    47  	// From configuration file
    48  	disabled bool
    49  
    50  	// system handlers
    51  	ifHandler linuxcalls.NetlinkAPI
    52  
    53  	// descriptors
    54  	ifDescriptor     *descriptor.InterfaceDescriptor
    55  	ifWatcher        *descriptor.InterfaceWatcher
    56  	ifAddrDescriptor *descriptor.InterfaceAddressDescriptor
    57  	ifVrfDescriptor  *descriptor.InterfaceVrfDescriptor
    58  
    59  	// index map
    60  	ifIndex ifaceidx.LinuxIfMetadataIndex
    61  
    62  	PushNotification func(notification *linux.Notification)
    63  }
    64  
    65  // Deps lists dependencies of the interface plugin.
    66  type Deps struct {
    67  	infra.PluginDeps
    68  	ServiceLabel servicelabel.ReaderAPI
    69  	KVScheduler  kvs.KVScheduler
    70  	NsPlugin     nsplugin.API
    71  	AddrAlloc    netalloc.AddressAllocator
    72  	VppIfPlugin  descriptor.VPPIfPluginAPI /* mandatory if TAP_TO_VPP interfaces are used */
    73  }
    74  
    75  // Config holds the ifplugin configuration.
    76  type Config struct {
    77  	Disabled      bool `json:"disabled"`
    78  	GoRoutinesCnt int  `json:"go-routines-count"`
    79  }
    80  
    81  // Init registers interface-related descriptors and starts watching of the default
    82  // network namespace for interface changes.
    83  func (p *IfPlugin) Init() error {
    84  	// parse configuration file
    85  	config, err := p.retrieveConfig()
    86  	if err != nil {
    87  		return err
    88  	}
    89  	p.Log.Debugf("Linux interface plugin config: %+v", config)
    90  	if config.Disabled {
    91  		p.disabled = true
    92  		p.Log.Infof("Disabling Linux Interface plugin")
    93  		return nil
    94  	}
    95  
    96  	// init & register interface descriptor
    97  	var ifDescriptor *kvs.KVDescriptor
    98  	ifDescriptor, p.ifDescriptor = descriptor.NewInterfaceDescriptor(p.ServiceLabel, p.NsPlugin, p.VppIfPlugin,
    99  		p.AddrAlloc, p.Log)
   100  	err = p.Deps.KVScheduler.RegisterKVDescriptor(ifDescriptor)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	// obtain read-only reference to index map
   106  	var withIndex bool
   107  	metadataMap := p.Deps.KVScheduler.GetMetadataMap(ifDescriptor.Name)
   108  	p.ifIndex, withIndex = metadataMap.(ifaceidx.LinuxIfMetadataIndex)
   109  	if !withIndex {
   110  		return errors.New("missing index with interface metadata")
   111  	}
   112  
   113  	// init handler and pass it to the interface descriptor
   114  	p.ifHandler = linuxcalls.NewNetLinkHandler(p.NsPlugin, p.ifIndex, p.ServiceLabel.GetAgentPrefix(),
   115  		config.GoRoutinesCnt, p.Log)
   116  	p.ifDescriptor.SetInterfaceHandler(p.ifHandler)
   117  
   118  	var addrDescriptor, vrfDescriptor *kvs.KVDescriptor
   119  	addrDescriptor, p.ifAddrDescriptor = descriptor.NewInterfaceAddressDescriptor(p.NsPlugin,
   120  		p.AddrAlloc, p.ifHandler, p.Log)
   121  	vrfDescriptor, p.ifVrfDescriptor = descriptor.NewInterfaceVrfDescriptor(p.NsPlugin, p.ifHandler, p.Log)
   122  	err = p.Deps.KVScheduler.RegisterKVDescriptor(addrDescriptor, vrfDescriptor)
   123  	if err != nil {
   124  		return err
   125  	}
   126  
   127  	notifyInterface := func(notif *linux_interfaces.InterfaceNotification) {
   128  		if p.PushNotification != nil {
   129  			p.PushNotification(&linux.Notification{
   130  				Interface: notif,
   131  			})
   132  		}
   133  	}
   134  	p.ifWatcher = descriptor.NewInterfaceWatcher(p.KVScheduler, p.ifHandler, notifyInterface, p.Log)
   135  	err = p.Deps.KVScheduler.RegisterKVDescriptor(p.ifWatcher.GetDescriptor())
   136  	if err != nil {
   137  		return err
   138  	}
   139  
   140  	// pass read-only index map to descriptors
   141  	p.ifDescriptor.SetInterfaceIndex(p.ifIndex)
   142  	p.ifAddrDescriptor.SetInterfaceIndex(p.ifIndex)
   143  	p.ifVrfDescriptor.SetInterfaceIndex(p.ifIndex)
   144  
   145  	// start interface watching
   146  	if err = p.ifWatcher.StartWatching(); err != nil {
   147  		return err
   148  	}
   149  
   150  	return nil
   151  }
   152  
   153  // Close stops watching of the default network namespace.
   154  func (p *IfPlugin) Close() error {
   155  	if p.disabled {
   156  		return nil
   157  	}
   158  	p.ifWatcher.StopWatching()
   159  	return nil
   160  }
   161  
   162  // GetInterfaceIndex gives read-only access to map with metadata of all configured
   163  // linux interfaces.
   164  func (p *IfPlugin) GetInterfaceIndex() ifaceidx.LinuxIfMetadataIndex {
   165  	return p.ifIndex
   166  }
   167  
   168  func (p *IfPlugin) SetNotifyService(notify func(notification *linux.Notification)) {
   169  	p.PushNotification = notify
   170  }
   171  
   172  // retrieveConfig loads IfPlugin configuration file.
   173  func (p *IfPlugin) retrieveConfig() (*Config, error) {
   174  	config := &Config{
   175  		// default configuration
   176  		GoRoutinesCnt: defaultGoRoutinesCnt,
   177  	}
   178  	found, err := p.Cfg.LoadValue(config)
   179  	if !found {
   180  		p.Log.Debug("Linux IfPlugin config not found")
   181  		return config, nil
   182  	}
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	p.Log.Debug("Linux IfPlugin config found")
   187  	return config, err
   188  }