go.ligato.io/vpp-agent/v3@v3.5.0/examples/localclient_vpp/nat/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 "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/vpp/localclient" 29 "go.ligato.io/vpp-agent/v3/cmd/vpp-agent/app" 30 "go.ligato.io/vpp-agent/v3/plugins/orchestrator" 31 vpp_intf "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 32 nat "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/nat" 33 ) 34 35 var ( 36 timeout = flag.Int("timeout", 20, "Timeout between applying of global and DNAT configuration in seconds") 37 ) 38 39 /* Configuration */ 40 41 // Basic NAT configuration consists of 3 parts: 42 // - Global NAT: NAT settings which are 'global' for the whole NAT44 environment, e.g. NAT forwarding setup 43 // - NAT-enabled interfaces (including output feature): each interface is configured individually 44 // - NAT address pools: each address pool can be configured individually 45 46 /* Result of the test NAT config */ 47 /* 48 vpp# sh nat44 interfaces 49 NAT44 interfaces: 50 memif1/3 in 51 memif1/1 out 52 memif1/2 output-feature out 53 54 vpp# sh nat44 addresses 55 NAT44 pool addresses: 56 10.10.0.1 57 tenant VRF: 0 58 0 busy udp ports 59 0 busy tcp ports 60 0 busy icmp ports 61 10.10.0.2 62 tenant VRF: 0 63 0 busy udp ports 64 0 busy tcp ports 65 0 busy icmp ports 66 175.124.0.1 67 tenant VRF: 0 68 0 busy udp ports 69 0 busy tcp ports 70 0 busy icmp ports 71 175.124.0.2 72 tenant VRF: 0 73 0 busy udp ports 74 0 busy tcp ports 75 0 busy icmp ports 76 175.124.0.3 77 tenant VRF: 0 78 0 busy udp ports 79 0 busy tcp ports 80 0 busy icmp ports 81 192.168.0.1 82 tenant VRF: 0 83 0 busy udp ports 84 0 busy tcp ports 85 0 busy icmp ports 86 NAT44 twice-nat pool addresses: 87 vpp# 88 */ 89 90 // DNAT puts static mapping (with or without load balancer) or identity mapping entries to the VPP. Destination 91 // address can be translated to one or more local addresses. If more than one local address is used, load 92 // balancer is configured automatically. 93 94 /* Result of DNAT test data */ 95 /* 96 vpp# sh nat44 static mappings 97 NAT44 static mappings: 98 udp vrf 0 external 192.168.0.1:8989 out2in-only 99 local 172.124.0.2:6500 probability 40 100 local 172.125.10.5:2300 probability 40 101 udp local 172.124.0.3:6501 external 192.47.21.1:8989 vrf 0 out2in-only 102 tcp local 10.10.0.1:2525 external 10.10.0.1:2525 vrf 0 103 vpp# 104 */ 105 106 /* Vpp-agent Init and Close*/ 107 108 // Start Agent plugins selected for this example. 109 func main() { 110 // Init close channel to stop the example. 111 exampleFinished := make(chan struct{}) 112 113 // Inject dependencies to example plugin 114 ep := &NatExamplePlugin{ 115 Log: logging.DefaultLogger, 116 VPP: app.DefaultVPP(), 117 Orchestrator: &orchestrator.DefaultPlugin, 118 } 119 120 // Start Agent 121 a := agent.NewAgent( 122 agent.AllPlugins(ep), 123 agent.QuitOnClose(exampleFinished), 124 ) 125 if err := a.Run(); err != nil { 126 log.Fatal() 127 } 128 129 go closeExample("localhost example finished", exampleFinished) 130 } 131 132 // Stop the agent with desired info message. 133 func closeExample(message string, exampleFinished chan struct{}) { 134 time.Sleep(time.Duration(*timeout+5) * time.Second) 135 logrus.DefaultLogger().Info(message) 136 close(exampleFinished) 137 } 138 139 /* NAT44 Example */ 140 141 // NatExamplePlugin uses localclient to transport example global NAT and DNAT and af-packet 142 // configuration to NAT VPP plugin 143 type NatExamplePlugin struct { 144 Log logging.Logger 145 app.VPP 146 Orchestrator *orchestrator.Plugin 147 148 wg sync.WaitGroup 149 cancel context.CancelFunc 150 } 151 152 // PluginName represents name of plugin. 153 const PluginName = "nat-example" 154 155 // Init initializes example plugin. 156 func (p *NatExamplePlugin) Init() error { 157 // Logger 158 p.Log = logrus.DefaultLogger() 159 p.Log.SetLevel(logging.DebugLevel) 160 p.Log.Info("Initializing NAT44 example") 161 162 // Flags 163 flag.Parse() 164 p.Log.Infof("Timeout between configuring NAT global and DNAT set to %d", *timeout) 165 166 p.Log.Info("NAT example initialization done") 167 return nil 168 } 169 170 // AfterInit initializes example plugin. 171 func (p *NatExamplePlugin) AfterInit() error { 172 // Apply initial VPP configuration. 173 p.putBasicNATConfig() 174 175 // Schedule reconfiguration. 176 var ctx context.Context 177 ctx, p.cancel = context.WithCancel(context.Background()) 178 p.wg.Add(1) 179 go p.putDNAT(ctx, *timeout) 180 181 return nil 182 } 183 184 // Close cleans up the resources. 185 func (p *NatExamplePlugin) Close() error { 186 p.cancel() 187 p.wg.Wait() 188 189 logrus.DefaultLogger().Info("Closed NAT example plugin") 190 return nil 191 } 192 193 // String returns plugin name 194 func (p *NatExamplePlugin) String() string { 195 return PluginName 196 } 197 198 // Configure NAT44 config 199 func (p *NatExamplePlugin) putBasicNATConfig() { 200 p.Log.Infof("Applying NAT44 configuration") 201 err := localclient.DataResyncRequest(PluginName). 202 Interface(interface1()). 203 Interface(interface2()). 204 Interface(interface3()). 205 NAT44Global(globalNat()). 206 NAT44Interface(natInterface1()). 207 NAT44Interface(natInterface2()). 208 NAT44Interface(natInterface3()). 209 NAT44AddressPool(natPool1()). 210 NAT44AddressPool(natPool2()). 211 NAT44AddressPool(natPool3()). 212 Send().ReceiveReply() 213 if err != nil { 214 p.Log.Errorf("NAT44 configuration failed: %v", err) 215 } else { 216 p.Log.Info("NAT44 configuration successful") 217 } 218 } 219 220 // Configure DNAT 221 func (p *NatExamplePlugin) putDNAT(ctx context.Context, timeout int) { 222 select { 223 case <-time.After(time.Duration(timeout) * time.Second): 224 p.Log.Infof("Applying DNAT configuration") 225 err := localclient.DataChangeRequest(PluginName). 226 Put(). 227 DNAT44(dNat()). 228 Send().ReceiveReply() 229 if err != nil { 230 p.Log.Errorf("DNAT configuration failed: %v", err) 231 } else { 232 p.Log.Info("DNAT configuration successful") 233 } 234 case <-ctx.Done(): 235 // Cancel the scheduled DNAT configuration. 236 p.Log.Info("DNAT configuration canceled") 237 } 238 p.wg.Done() 239 } 240 241 /* Example Data */ 242 243 func interface1() *vpp_intf.Interface { 244 return &vpp_intf.Interface{ 245 Name: "memif1", 246 Type: vpp_intf.Interface_MEMIF, 247 Enabled: true, 248 Mtu: 1478, 249 IpAddresses: []string{ 250 "172.125.40.1/24", 251 }, 252 Link: &vpp_intf.Interface_Memif{ 253 Memif: &vpp_intf.MemifLink{ 254 Id: 1, 255 Secret: "secret1", 256 Master: false, 257 SocketFilename: "/tmp/memif1.sock", 258 }, 259 }, 260 } 261 } 262 263 func interface2() *vpp_intf.Interface { 264 return &vpp_intf.Interface{ 265 Name: "memif2", 266 Type: vpp_intf.Interface_MEMIF, 267 Enabled: true, 268 Mtu: 1478, 269 IpAddresses: []string{ 270 "192.47.21.1/24", 271 }, 272 Link: &vpp_intf.Interface_Memif{ 273 Memif: &vpp_intf.MemifLink{ 274 Id: 2, 275 Secret: "secret2", 276 Master: false, 277 SocketFilename: "/tmp/memif1.sock", 278 }, 279 }, 280 } 281 } 282 283 func interface3() *vpp_intf.Interface { 284 return &vpp_intf.Interface{ 285 Name: "memif3", 286 Type: vpp_intf.Interface_MEMIF, 287 Enabled: true, 288 Mtu: 1478, 289 IpAddresses: []string{ 290 "94.18.21.1/24", 291 }, 292 Link: &vpp_intf.Interface_Memif{ 293 Memif: &vpp_intf.MemifLink{ 294 Id: 3, 295 Secret: "secret3", 296 Master: false, 297 SocketFilename: "/tmp/memif1.sock", 298 }, 299 }, 300 } 301 } 302 303 func globalNat() *nat.Nat44Global { 304 return &nat.Nat44Global{ 305 Forwarding: false, 306 } 307 } 308 309 func natInterface1() *nat.Nat44Interface { 310 return &nat.Nat44Interface{ 311 Name: "memif1", 312 NatOutside: true, 313 } 314 } 315 316 func natInterface2() *nat.Nat44Interface { 317 return &nat.Nat44Interface{ 318 Name: "memif2", 319 NatOutside: true, 320 OutputFeature: true, 321 } 322 } 323 324 func natInterface3() *nat.Nat44Interface { 325 return &nat.Nat44Interface{ 326 Name: "memif3", 327 NatInside: true, 328 } 329 } 330 331 func natPool1() *nat.Nat44AddressPool { 332 return &nat.Nat44AddressPool{ 333 VrfId: 0, 334 FirstIp: "192.168.0.1", 335 } 336 } 337 338 func natPool2() *nat.Nat44AddressPool { 339 return &nat.Nat44AddressPool{ 340 VrfId: 0, 341 FirstIp: "175.124.0.1", 342 LastIp: "175.124.0.3", 343 } 344 } 345 346 func natPool3() *nat.Nat44AddressPool { 347 return &nat.Nat44AddressPool{ 348 VrfId: 0, 349 FirstIp: "10.10.0.1", 350 LastIp: "10.10.0.2", 351 } 352 } 353 354 func dNat() *nat.DNat44 { 355 return &nat.DNat44{ 356 Label: "dnat1", 357 StMappings: []*nat.DNat44_StaticMapping{ 358 { 359 // DNAT static mapping with load balancer (multiple local addresses) 360 ExternalInterface: "memif1", 361 ExternalIp: "192.168.0.1", 362 ExternalPort: 8989, 363 LocalIps: []*nat.DNat44_StaticMapping_LocalIP{ 364 { 365 VrfId: 0, 366 LocalIp: "172.124.0.2", 367 LocalPort: 6500, 368 Probability: 40, 369 }, 370 { 371 VrfId: 0, 372 LocalIp: "172.125.10.5", 373 LocalPort: 2300, 374 Probability: 40, 375 }, 376 }, 377 Protocol: 1, 378 //TwiceNat: nat.DNat44_StaticMapping_ENABLED, 379 }, 380 { 381 // DNAT static mapping without load balancer (single local address) 382 ExternalInterface: "memif2", 383 ExternalIp: "192.168.0.2", 384 ExternalPort: 8989, 385 LocalIps: []*nat.DNat44_StaticMapping_LocalIP{ 386 { 387 VrfId: 0, 388 LocalIp: "172.124.0.3", 389 LocalPort: 6501, 390 Probability: 50, 391 }, 392 }, 393 Protocol: 1, 394 //TwiceNat: nat.DNat44_StaticMapping_ENABLED, 395 }, 396 }, 397 IdMappings: []*nat.DNat44_IdentityMapping{ 398 { 399 VrfId: 0, 400 IpAddress: "10.10.0.1", 401 Port: 2525, 402 Protocol: 0, 403 }, 404 }, 405 } 406 }