go.ligato.io/vpp-agent/v3@v3.5.0/examples/localclient_linux/vrf/main.go (about) 1 // Copyright (c) 2021 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 package main 16 17 import ( 18 "context" 19 "log" 20 "sync" 21 "time" 22 23 "github.com/namsral/flag" 24 "go.ligato.io/cn-infra/v2/agent" 25 "go.ligato.io/cn-infra/v2/logging" 26 "go.ligato.io/cn-infra/v2/logging/logrus" 27 28 "go.ligato.io/vpp-agent/v3/clientv2/linux/localclient" 29 "go.ligato.io/vpp-agent/v3/cmd/vpp-agent/app" 30 linux_ifplugin "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin" 31 linux_nsplugin "go.ligato.io/vpp-agent/v3/plugins/linux/nsplugin" 32 "go.ligato.io/vpp-agent/v3/plugins/orchestrator" 33 vpp_ifplugin "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin" 34 linux_intf "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces" 35 vpp_intf "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 36 ) 37 38 var ( 39 timeout = flag.Int("timeout", 20, "Timeout between applying of initial and modified configuration in seconds") 40 ) 41 42 /* Confgiuration */ 43 44 // Example configures two VRF devices. Then two TAP interfaces on the vpp with other ends in the default namespace. 45 // Both Linux taps are set with IP address 46 /********************************************** 47 * Initial Data * 48 * * 49 * +--------------------------------------+ * 50 * | | * 51 * | +-------+ +-------+ | * 52 * | | tap1 | | tap2 | | * 53 * | +---+---+ +---+---+ | * 54 * | | | | * 55 * +-------+------------------------------+ * 56 * | | * 57 * +-------+---------+ +-------+--------+ * 58 * | linux-tap1 | | linux-tap1 | * 59 * | IP: 10.0.0.2/24 | | IP: 20.0.0.2/24| * 60 * +-----------------+ +----------------+ * 61 * VRF-dev-1 VRF-dev-2 * 62 * * 63 **********************************************/ 64 65 // Next step switches Linux TAP VRFs 66 /********************************************** 67 * Initial Data * 68 * * 69 * +--------------------------------------+ * 70 * | | * 71 * | +-------+ +-------+ | * 72 * | | tap1 | | tap2 | | * 73 * | +---+---+ +---+---+ | * 74 * | | | | * 75 * +-------+------------------------------+ * 76 * | | * 77 * +-------+---------+ +-------+--------+ * 78 * | linux-tap1 | | linux-tap1 | * 79 * | IP: 10.0.0.2/24 | | IP: 20.0.0.2/24| * 80 * +-----------------+ +----------------+ * 81 * VRF-dev-2 VRF-dev-1 * 82 * * 83 **********************************************/ 84 85 /* Vpp-agent Init and Close*/ 86 87 // Start Agent plugins selected for this example. 88 func main() { 89 // Set inter-dependency between VPP & Linux plugins 90 vpp_ifplugin.DefaultPlugin.LinuxIfPlugin = &linux_ifplugin.DefaultPlugin 91 vpp_ifplugin.DefaultPlugin.NsPlugin = &linux_nsplugin.DefaultPlugin 92 linux_ifplugin.DefaultPlugin.VppIfPlugin = &vpp_ifplugin.DefaultPlugin 93 94 // Init close channel to stop the example. 95 exampleFinished := make(chan struct{}) 96 97 // Inject dependencies to example plugin 98 ep := &VrfExamplePlugin{ 99 Log: logging.DefaultLogger, 100 VPP: app.DefaultVPP(), 101 Linux: app.DefaultLinux(), 102 Orchestrator: &orchestrator.DefaultPlugin, 103 } 104 105 // Start Agent 106 a := agent.NewAgent( 107 agent.AllPlugins(ep), 108 agent.QuitOnClose(exampleFinished), 109 ) 110 if err := a.Run(); err != nil { 111 log.Fatal(err) 112 } 113 114 go closeExample("VRF localhost example finished", exampleFinished) 115 } 116 117 // Stop the agent with desired info message. 118 func closeExample(message string, exampleFinished chan struct{}) { 119 time.Sleep(time.Duration(*timeout+5) * time.Second) 120 logrus.DefaultLogger().Info(message) 121 close(exampleFinished) 122 } 123 124 /* VRF Example */ 125 126 // VrfExamplePlugin uses localclient to transport example vrf, tap and its linux part 127 // configuration to linuxplugin or VPP plugins 128 type VrfExamplePlugin struct { 129 Log logging.Logger 130 app.VPP 131 app.Linux 132 Orchestrator *orchestrator.Plugin 133 134 wg sync.WaitGroup 135 cancelResync context.CancelFunc 136 cancelModified context.CancelFunc 137 } 138 139 // PluginName represents name of plugin. 140 const PluginName = "vrf-example" 141 142 // Init initializes example plugin. 143 func (p *VrfExamplePlugin) Init() error { 144 // Logger 145 p.Log = logrus.DefaultLogger() 146 p.Log.SetLevel(logging.DebugLevel) 147 p.Log.Info("Initializing VRF device example") 148 149 // Flags 150 flag.Parse() 151 p.Log.Infof("Timeout between create and modify set to %d", *timeout) 152 153 p.Log.Info("VRF example initialization done") 154 return nil 155 } 156 157 // AfterInit initializes example plugin. 158 func (p *VrfExamplePlugin) AfterInit() error { 159 // Apply initial Linux/VPP configuration 160 p.putInitialData() 161 162 // Schedule VRF resync 163 var ctx context.Context 164 ctx, p.cancelResync = context.WithCancel(context.Background()) 165 p.wg.Add(1) 166 go p.resync(ctx, *timeout) 167 168 // Schedule reconfiguration 169 ctx, p.cancelModified = context.WithCancel(context.Background()) 170 p.wg.Add(1) 171 go p.putModifiedData(ctx, *timeout*2) 172 173 return nil 174 } 175 176 // Close cleans up the resources. 177 func (p *VrfExamplePlugin) Close() error { 178 p.cancelResync() 179 p.cancelModified() 180 p.wg.Wait() 181 182 p.Log.Info("Closed VRF plugin") 183 return nil 184 } 185 186 // String returns plugin name 187 func (p *VrfExamplePlugin) String() string { 188 return PluginName 189 } 190 191 // Configure initial data 192 func (p *VrfExamplePlugin) putInitialData() { 193 p.Log.Infof("Applying initial configuration") 194 err := localclient.DataResyncRequest(PluginName). 195 LinuxInterface(vrf1()). 196 LinuxInterface(vrf2()). 197 VppInterface(tap1()). 198 LinuxInterface(linuxTap1()). 199 VppInterface(tap2()). 200 LinuxInterface(linuxTap2()). 201 Send().ReceiveReply() 202 if err != nil { 203 p.Log.Errorf("Initial configuration failed: %v", err) 204 } else { 205 p.Log.Info("Initial configuration successful") 206 } 207 } 208 209 // Configure modified data 210 // This step serves as a MTU check for various kernels. After the resync, vrf1's 211 // MTU should be 65575 and vrf2's MTU 65536 212 func (p *VrfExamplePlugin) resync(ctx context.Context, timeout int) { 213 select { 214 case <-time.After(time.Duration(timeout) * time.Second): 215 p.Log.Infof("Applying resync VRFs") 216 // Simulate configuration change after timeout 217 err := localclient.DataResyncRequest(PluginName). 218 LinuxInterface(vrf1()). 219 LinuxInterface(vrf2()). 220 VppInterface(tap1()). 221 LinuxInterface(linuxTap1()). 222 VppInterface(tap2()). 223 LinuxInterface(linuxTap2()). 224 Send().ReceiveReply() 225 if err != nil { 226 p.Log.Errorf("Resync failed: %v", err) 227 } else { 228 p.Log.Info("Resync successful") 229 } 230 case <-ctx.Done(): 231 // Cancel the scheduled re-configuration. 232 p.Log.Info("Resync of configuration canceled") 233 } 234 p.wg.Done() 235 } 236 237 // Configure modified data 238 func (p *VrfExamplePlugin) putModifiedData(ctx context.Context, timeout int) { 239 select { 240 case <-time.After(time.Duration(timeout) * time.Second): 241 p.Log.Infof("Applying modified configuration") 242 // Simulate configuration change after timeout 243 err := localclient.DataChangeRequest(PluginName). 244 Put(). 245 LinuxInterface(modifiedLinuxTap1()). 246 LinuxInterface(modifiedLinuxTap2()). 247 Send().ReceiveReply() 248 if err != nil { 249 p.Log.Errorf("Modified configuration failed: %v", err) 250 } else { 251 p.Log.Info("Modified configuration successful") 252 } 253 case <-ctx.Done(): 254 // Cancel the scheduled re-configuration. 255 p.Log.Info("Modification of configuration canceled") 256 } 257 p.wg.Done() 258 } 259 260 /* Example Data */ 261 262 func vrf1() *linux_intf.Interface { 263 return &linux_intf.Interface{ 264 Name: "vrf1", 265 Type: linux_intf.Interface_VRF_DEVICE, 266 Enabled: true, 267 Link: &linux_intf.Interface_VrfDev{ 268 VrfDev: &linux_intf.VrfDevLink{ 269 RoutingTable: 1, 270 }, 271 }, 272 } 273 } 274 275 func vrf2() *linux_intf.Interface { 276 return &linux_intf.Interface{ 277 Name: "vrf2", 278 Type: linux_intf.Interface_VRF_DEVICE, 279 Enabled: true, 280 Mtu: 65536, // simulate old kernel's default 281 Link: &linux_intf.Interface_VrfDev{ 282 VrfDev: &linux_intf.VrfDevLink{ 283 RoutingTable: 2, 284 }, 285 }, 286 } 287 } 288 289 func tap1() *vpp_intf.Interface { 290 return &vpp_intf.Interface{ 291 Name: "tap1", 292 Type: vpp_intf.Interface_TAP, 293 Enabled: true, 294 PhysAddress: "D5:BC:DC:12:E4:0E", 295 IpAddresses: []string{ 296 "10.0.0.11/24", 297 }, 298 Link: &vpp_intf.Interface_Tap{ 299 Tap: &vpp_intf.TapLink{ 300 Version: 2, 301 }, 302 }, 303 } 304 } 305 306 func linuxTap1() *linux_intf.Interface { 307 return &linux_intf.Interface{ 308 Name: "linux-tap1", 309 Type: linux_intf.Interface_TAP_TO_VPP, 310 Enabled: true, 311 PhysAddress: "88:88:88:88:88:88", 312 IpAddresses: []string{ 313 "10.0.0.2/24", 314 }, 315 HostIfName: "tap_to_vpp1", 316 VrfMasterInterface: "vrf1", 317 Link: &linux_intf.Interface_Tap{ 318 Tap: &linux_intf.TapLink{ 319 VppTapIfName: "tap1", 320 }, 321 }, 322 } 323 } 324 325 func modifiedLinuxTap1() *linux_intf.Interface { 326 return &linux_intf.Interface{ 327 Name: "linux-tap1", 328 Type: linux_intf.Interface_TAP_TO_VPP, 329 Enabled: true, 330 PhysAddress: "88:88:88:88:88:88", 331 IpAddresses: []string{ 332 "10.0.0.2/24", 333 }, 334 HostIfName: "tap_to_vpp1", 335 VrfMasterInterface: "vrf2", 336 Link: &linux_intf.Interface_Tap{ 337 Tap: &linux_intf.TapLink{ 338 VppTapIfName: "tap1", 339 }, 340 }, 341 } 342 } 343 344 func tap2() *vpp_intf.Interface { 345 return &vpp_intf.Interface{ 346 Name: "tap2", 347 Type: vpp_intf.Interface_TAP, 348 Enabled: true, 349 PhysAddress: "D5:BC:DC:12:E4:0E", 350 IpAddresses: []string{ 351 "20.0.0.11/24", 352 }, 353 Link: &vpp_intf.Interface_Tap{ 354 Tap: &vpp_intf.TapLink{ 355 Version: 2, 356 }, 357 }, 358 } 359 } 360 361 func linuxTap2() *linux_intf.Interface { 362 return &linux_intf.Interface{ 363 Name: "linux-tap2", 364 Type: linux_intf.Interface_TAP_TO_VPP, 365 Enabled: true, 366 PhysAddress: "88:88:88:88:88:88", 367 IpAddresses: []string{ 368 "20.0.0.2/24", 369 }, 370 HostIfName: "tap_to_vpp2", 371 VrfMasterInterface: "vrf2", 372 Link: &linux_intf.Interface_Tap{ 373 Tap: &linux_intf.TapLink{ 374 VppTapIfName: "tap2", 375 }, 376 }, 377 } 378 } 379 380 func modifiedLinuxTap2() *linux_intf.Interface { 381 return &linux_intf.Interface{ 382 Name: "linux-tap2", 383 Type: linux_intf.Interface_TAP_TO_VPP, 384 Enabled: true, 385 PhysAddress: "88:88:88:88:88:88", 386 IpAddresses: []string{ 387 "20.0.0.2/24", 388 }, 389 HostIfName: "tap_to_vpp2", 390 VrfMasterInterface: "vrf1", 391 Link: &linux_intf.Interface_Tap{ 392 Tap: &linux_intf.TapLink{ 393 VppTapIfName: "tap2", 394 }, 395 }, 396 } 397 }