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  }