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 }