go.ligato.io/vpp-agent/v3@v3.5.0/examples/localclient_linux/veth/main.go (about) 1 // Copyright (c) 2017 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 "sync" 20 "time" 21 22 "log" 23 24 "github.com/namsral/flag" 25 "go.ligato.io/cn-infra/v2/agent" 26 "go.ligato.io/cn-infra/v2/logging" 27 "go.ligato.io/cn-infra/v2/logging/logrus" 28 29 localclient2 "go.ligato.io/vpp-agent/v3/clientv2/linux/localclient" 30 "go.ligato.io/vpp-agent/v3/cmd/vpp-agent/app" 31 linux_ifplugin "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin" 32 linux_nsplugin "go.ligato.io/vpp-agent/v3/plugins/linux/nsplugin" 33 "go.ligato.io/vpp-agent/v3/plugins/orchestrator" 34 vpp_ifplugin "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin" 35 linux_intf "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces" 36 linux_namespace "go.ligato.io/vpp-agent/v3/proto/ligato/linux/namespace" 37 vpp_intf "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 38 vpp_l2 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l2" 39 ) 40 41 var ( 42 timeout = flag.Int("timeout", 20, "Timeout between applying of initial and modified configuration in seconds") 43 ) 44 45 /* Confgiuration */ 46 47 // Initial Data configures single veth pair where both linux interfaces veth11 and veth12 are configured in 48 // default namespace. Af packet interface is attached to veth11 and put to the bridge domain. The bridge domain 49 // will contain a second af packet which will be created in the second iteration (modify). 50 /********************************************** 51 * Initial Data * 52 * * 53 * +--------------------------------------+ * 54 * | +-- Bridge Domain --+ | * 55 * | | | | * 56 * | +------------+ | | * 57 * | | afpacket1 | (afpacket2) | * 58 * | +-----+------+ | * 59 * | | | * 60 * +-------+------------------------------+ * 61 * | * 62 * +-------+--------+ * 63 * | veth11 | * 64 * | DEFAULT CONFIG | * 65 * +-------+--------+ * 66 * | * 67 * +-------+---------+ * 68 * | veth12 | * 69 * | IP: 10.0.0.1/24 | * 70 * | DEFAULT NS | * 71 * +-----------------+ * 72 * * 73 **********************************************/ 74 75 // Modify changes MTU of the veth11, moves veth12 to the namespace ns1 and configures IP address to it. Also second 76 // branch veth21 - veth22 is configured including afpacket2. The new af packet is in the same bridge domain. This 77 // configuration allows to ping between veth12 and veth22 interfaces 78 /*********************************************** 79 * Modified Data * 80 * * 81 * +---------------------------------------+ * 82 * | +-- Bridge domain --+ | * 83 * | | | | * 84 * | +-----+------+ +-----+------+ | * 85 * | | afpacket1 | | afpacket2 | | * 86 * | +-----+------+ +-----+------+ | * 87 * | | | | * 88 * +-------+-------------------+-----------+ * 89 * | | * 90 * +-------+--------+ +-------+--------+ * 91 * | veth11 | | veth21 | * 92 * | MTU: 1000 | | DEFAULT CONFIG | * 93 * +-------+--------+ +-------+--------+ * 94 * | | * 95 * +-------+---------+ +-------+---------+ * 96 * | veth12 | | veth22 | * 97 * | IP: 10.0.0.1/24 | | IP: 10.0.0.2/24 | * 98 * | NAMESPACE: ns1 | | NAMESPACE: ns2 | * 99 * +-----------------+ +-----------------+ * 100 ***********************************************/ 101 102 /* Vpp-agent Init and Close*/ 103 104 // PluginName represents name of plugin. 105 const PluginName = "veth-example" 106 107 // Start Agent plugins selected for this example. 108 func main() { 109 // Set inter-dependency between VPP & Linux plugins 110 vpp_ifplugin.DefaultPlugin.LinuxIfPlugin = &linux_ifplugin.DefaultPlugin 111 vpp_ifplugin.DefaultPlugin.NsPlugin = &linux_nsplugin.DefaultPlugin 112 linux_ifplugin.DefaultPlugin.VppIfPlugin = &vpp_ifplugin.DefaultPlugin 113 114 // Init close channel to stop the example. 115 exampleFinished := make(chan struct{}) 116 117 // Inject dependencies to example plugin 118 ep := &VethExamplePlugin{ 119 Log: logging.DefaultLogger, 120 VPP: app.DefaultVPP(), 121 Linux: app.DefaultLinux(), 122 Orchestrator: &orchestrator.DefaultPlugin, 123 } 124 125 // Start Agent 126 a := agent.NewAgent( 127 agent.AllPlugins(ep), 128 agent.QuitOnClose(exampleFinished), 129 ) 130 if err := a.Run(); err != nil { 131 log.Fatal() 132 } 133 134 go closeExample("localhost example finished", exampleFinished) 135 } 136 137 // Stop the agent with desired info message. 138 func closeExample(message string, exampleFinished chan struct{}) { 139 time.Sleep(time.Duration(*timeout+5) * time.Second) 140 logrus.DefaultLogger().Info(message) 141 close(exampleFinished) 142 } 143 144 /* VETH Example */ 145 146 // VethExamplePlugin uses localclient to transport example veth and af-packet 147 // configuration to linuxplugin, eventually VPP plugins 148 type VethExamplePlugin struct { 149 Log logging.Logger 150 app.VPP 151 app.Linux 152 Orchestrator *orchestrator.Plugin 153 154 wg sync.WaitGroup 155 cancel context.CancelFunc 156 } 157 158 // String returns plugin name 159 func (p *VethExamplePlugin) String() string { 160 return PluginName 161 } 162 163 // Init initializes example plugin. 164 func (p *VethExamplePlugin) Init() error { 165 // Logger 166 p.Log = logrus.DefaultLogger() 167 p.Log.SetLevel(logging.DebugLevel) 168 p.Log.Info("Initializing Veth example") 169 170 // Flags 171 flag.Parse() 172 p.Log.Infof("Timeout between create and modify set to %d", *timeout) 173 174 p.Log.Info("Veth example initialization done") 175 return nil 176 } 177 178 // AfterInit initializes example plugin. 179 func (p *VethExamplePlugin) AfterInit() error { 180 // Apply initial Linux/VPP configuration. 181 p.putInitialData() 182 183 // Schedule reconfiguration. 184 var ctx context.Context 185 ctx, p.cancel = context.WithCancel(context.Background()) 186 p.wg.Add(1) 187 go p.putModifiedData(ctx, *timeout) 188 189 return nil 190 } 191 192 // Close cleans up the resources. 193 func (p *VethExamplePlugin) Close() error { 194 p.cancel() 195 p.wg.Wait() 196 197 p.Log.Info("Closed Veth plugin") 198 return nil 199 } 200 201 // Configure initial data 202 func (p *VethExamplePlugin) putInitialData() { 203 p.Log.Infof("Applying initial configuration") 204 err := localclient2.DataResyncRequest(PluginName). 205 LinuxInterface(initialVeth11()). 206 LinuxInterface(initialVeth12()). 207 VppInterface(afPacket1()). 208 BD(bridgeDomain()). 209 Send().ReceiveReply() 210 if err != nil { 211 p.Log.Errorf("Initial configuration failed: %v", err) 212 } else { 213 p.Log.Info("Initial configuration successful") 214 } 215 } 216 217 // Configure modified data 218 func (p *VethExamplePlugin) putModifiedData(ctx context.Context, timeout int) { 219 select { 220 case <-time.After(time.Duration(timeout) * time.Second): 221 p.Log.Infof("Applying modified configuration") 222 // Simulate configuration change after timeout 223 err := localclient2.DataChangeRequest(PluginName). 224 Put(). 225 LinuxInterface(modifiedVeth11()). 226 LinuxInterface(modifiedVeth12()). 227 LinuxInterface(veth21()). 228 LinuxInterface(veth22()). 229 VppInterface(afPacket2()). 230 Send().ReceiveReply() 231 if err != nil { 232 p.Log.Errorf("Modified configuration failed: %v", err) 233 } else { 234 p.Log.Info("Modified configuration successful") 235 } 236 case <-ctx.Done(): 237 // Cancel the scheduled re-configuration. 238 p.Log.Info("Modification of configuration canceled") 239 } 240 p.wg.Done() 241 } 242 243 /* Example Data */ 244 245 func initialVeth11() *linux_intf.Interface { 246 return &linux_intf.Interface{ 247 Name: "veth11", 248 Type: linux_intf.Interface_VETH, 249 Enabled: true, 250 Link: &linux_intf.Interface_Veth{ 251 Veth: &linux_intf.VethLink{PeerIfName: "veth12"}, 252 }, 253 } 254 } 255 256 func modifiedVeth11() *linux_intf.Interface { 257 return &linux_intf.Interface{ 258 Name: "veth11", 259 Type: linux_intf.Interface_VETH, 260 Enabled: true, 261 Link: &linux_intf.Interface_Veth{ 262 Veth: &linux_intf.VethLink{PeerIfName: "veth12"}, 263 }, 264 Mtu: 1000, 265 } 266 } 267 268 func initialVeth12() *linux_intf.Interface { 269 return &linux_intf.Interface{ 270 Name: "veth12", 271 Type: linux_intf.Interface_VETH, 272 Enabled: true, 273 Link: &linux_intf.Interface_Veth{ 274 Veth: &linux_intf.VethLink{PeerIfName: "veth11"}, 275 }, 276 } 277 } 278 279 func modifiedVeth12() *linux_intf.Interface { 280 return &linux_intf.Interface{ 281 Name: "veth12", 282 Type: linux_intf.Interface_VETH, 283 Enabled: true, 284 Link: &linux_intf.Interface_Veth{ 285 Veth: &linux_intf.VethLink{PeerIfName: "veth11"}, 286 }, 287 IpAddresses: []string{"10.0.0.1/24"}, 288 PhysAddress: "D2:74:8C:12:67:D2", 289 Namespace: &linux_namespace.NetNamespace{ 290 Reference: "ns1", 291 Type: linux_namespace.NetNamespace_NSID, 292 }, 293 } 294 } 295 296 func veth21() *linux_intf.Interface { 297 return &linux_intf.Interface{ 298 Name: "veth21", 299 Type: linux_intf.Interface_VETH, 300 Enabled: true, 301 Link: &linux_intf.Interface_Veth{ 302 Veth: &linux_intf.VethLink{PeerIfName: "veth22"}, 303 }, 304 } 305 } 306 307 func veth22() *linux_intf.Interface { 308 return &linux_intf.Interface{ 309 Name: "veth22", 310 Type: linux_intf.Interface_VETH, 311 Enabled: true, 312 Link: &linux_intf.Interface_Veth{ 313 Veth: &linux_intf.VethLink{PeerIfName: "veth21"}, 314 }, 315 IpAddresses: []string{"10.0.0.2/24"}, 316 PhysAddress: "92:C7:42:67:AB:CD", 317 Namespace: &linux_namespace.NetNamespace{ 318 Reference: "ns2", 319 Type: linux_namespace.NetNamespace_NSID, 320 }, 321 } 322 } 323 324 func afPacket1() *vpp_intf.Interface { 325 return &vpp_intf.Interface{ 326 Name: "afpacket1", 327 Type: vpp_intf.Interface_AF_PACKET, 328 Enabled: true, 329 Link: &vpp_intf.Interface_Afpacket{ 330 Afpacket: &vpp_intf.AfpacketLink{ 331 HostIfName: "veth11", 332 }, 333 }, 334 } 335 } 336 337 func afPacket2() *vpp_intf.Interface { 338 return &vpp_intf.Interface{ 339 Name: "afpacket2", 340 Type: vpp_intf.Interface_AF_PACKET, 341 Enabled: true, 342 Link: &vpp_intf.Interface_Afpacket{ 343 Afpacket: &vpp_intf.AfpacketLink{ 344 HostIfName: "veth21", 345 }, 346 }, 347 } 348 } 349 350 func bridgeDomain() *vpp_l2.BridgeDomain { 351 return &vpp_l2.BridgeDomain{ 352 Name: "br1", 353 Flood: true, 354 UnknownUnicastFlood: true, 355 Forward: true, 356 Learn: true, 357 ArpTermination: false, 358 MacAge: 0, /* means disable aging */ 359 Interfaces: []*vpp_l2.BridgeDomain_Interface{ 360 { 361 Name: "afpacket1", 362 BridgedVirtualInterface: false, 363 }, { 364 Name: "afpacket2", 365 BridgedVirtualInterface: false, 366 }, 367 }, 368 } 369 }