go.ligato.io/vpp-agent/v3@v3.5.0/tests/integration/vpp/160_wireguard_test.go (about)

     1  //  Copyright (c) 2020 Doc.ai 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 vpp
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  
    21  	"go.ligato.io/cn-infra/v2/logging/logrus"
    22  
    23  	_ "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin"
    24  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx"
    25  	ifplugin_vppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls"
    26  	_ "go.ligato.io/vpp-agent/v3/plugins/vpp/wireguardplugin"
    27  	wgplugin_vppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/wireguardplugin/vppcalls"
    28  	interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    29  	wg "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/wireguard"
    30  )
    31  
    32  type testEntry struct {
    33  	name       string
    34  	wgInt      *interfaces.WireguardLink
    35  	wgInt2     *interfaces.WireguardLink
    36  	peer       *wg.Peer
    37  	peer2      *wg.Peer
    38  	shouldFail bool
    39  	skip       string
    40  	skipFor    string
    41  }
    42  
    43  func TestWireguard(t *testing.T) {
    44  	ctx := setupVPP(t)
    45  	defer ctx.teardownVPP()
    46  
    47  	release := ctx.versionInfo.Release()
    48  	if release < "20.09" {
    49  		t.Skipf("Wireguard: skipped for VPP < 20.09 (%s)", release)
    50  	}
    51  
    52  	ifHandler := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.vppClient, logrus.NewLogger("test"))
    53  	ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test"), "test-ifidx")
    54  
    55  	tests := []testEntry{
    56  		{
    57  			name: "Create Wireguard tunnel (IPv4)",
    58  			wgInt: &interfaces.WireguardLink{
    59  				PrivateKey: "gIjXzrQfIFf80d0O8Hd2KhcfkKLRncc+8C70OjotIW8=",
    60  				Port:       12312,
    61  				SrcAddr:    "10.10.0.1",
    62  			},
    63  			shouldFail: false,
    64  		},
    65  		{
    66  			name: "Create Wireguard tunnel with invalid privateKey",
    67  			wgInt: &interfaces.WireguardLink{
    68  				PrivateKey: "d0O8Hd2KhcfkKLRncc+8C70OjotIW8=",
    69  				Port:       12312,
    70  				SrcAddr:    "10.10.0.1",
    71  			},
    72  			shouldFail: true,
    73  		},
    74  		{
    75  			name: "Create Wireguard 2 tunnels (IPv4)",
    76  			wgInt: &interfaces.WireguardLink{
    77  				PrivateKey: "gIjXzrQfIFf80d0O8Hd2KhcfkKLRncc+8C70OjotIW8=",
    78  				Port:       12322,
    79  				SrcAddr:    "10.10.0.1",
    80  			},
    81  			wgInt2: &interfaces.WireguardLink{
    82  				PrivateKey: "qDUQL8I5RNMWfbi3qgFs237FYD+SyZTj5g0Ix3qRvGs=",
    83  				Port:       12323,
    84  				SrcAddr:    "10.11.0.1",
    85  			},
    86  			shouldFail: false,
    87  		},
    88  		{
    89  			name: "Create Wireguard tunnel with peer",
    90  			wgInt: &interfaces.WireguardLink{
    91  				PrivateKey: "gIjXzrQfIFf80d0O8Hd2KhcfkKLRncc+8C70OjotIW8=",
    92  				Port:       12332,
    93  				SrcAddr:    "10.10.0.1",
    94  			},
    95  			peer: &wg.Peer{
    96  				PublicKey:           "dIjXzrQfIFf80d0O8Hd2KhcfkKLRncc+8C70OjotIW8=",
    97  				WgIfName:            "wg3",
    98  				Port:                12314,
    99  				PersistentKeepalive: 10,
   100  				Endpoint:            "10.10.0.2",
   101  				Flags:               0,
   102  				AllowedIps:          []string{"10.10.0.0/24"},
   103  			},
   104  			shouldFail: false,
   105  		},
   106  		{
   107  			name: "Create Wireguard tunnel with 2 itfs and 2 peers",
   108  			wgInt: &interfaces.WireguardLink{
   109  				PrivateKey: "gIjXzrQfIFf80d0O8Hd2KhcfkKLRncc+8C70OjotIW8=",
   110  				Port:       12342,
   111  				SrcAddr:    "10.10.0.1",
   112  			},
   113  			wgInt2: &interfaces.WireguardLink{
   114  				PrivateKey: "qDUQL8I5RNMWfbi3qgFs237FYD+SyZTj5g0Ix3qRvGs=",
   115  				Port:       12343,
   116  				SrcAddr:    "10.11.0.1",
   117  			},
   118  			peer: &wg.Peer{
   119  				PublicKey:           "dIjXzrQfIFf80d0O8Hd2KhcfkKLRncc+8C70OjotIW8=",
   120  				WgIfName:            "wg4",
   121  				Port:                12314,
   122  				PersistentKeepalive: 10,
   123  				Endpoint:            "10.10.0.2",
   124  				Flags:               0,
   125  				AllowedIps:          []string{"10.10.0.0/24"},
   126  			},
   127  			peer2: &wg.Peer{
   128  				PublicKey:           "33GyVvUQalLCscTfN8TxtTp/ixtSWg55PhHy0aWABHQ=",
   129  				WgIfName:            "wg4-2",
   130  				Port:                12314,
   131  				PersistentKeepalive: 10,
   132  				Endpoint:            "10.11.0.2",
   133  				Flags:               0,
   134  				AllowedIps:          []string{"10.11.0.0/24"},
   135  			},
   136  			shouldFail: false,
   137  		},
   138  	}
   139  	for i, test := range tests {
   140  		t.Run(test.name, func(t *testing.T) {
   141  			if test.skipFor != "" && ctx.versionInfo.Release() == test.skipFor {
   142  				t.Skipf("SKIP for VPP %s: %s", test.skipFor, test.skip)
   143  			}
   144  
   145  			ifIndexes.Clear()
   146  
   147  			ifName := fmt.Sprintf("wg%d", i)
   148  			ifIdx, err := ifHandler.AddWireguardTunnel(ifName, test.wgInt)
   149  
   150  			ifIndexes.Put(ifName, &ifaceidx.IfaceMetadata{
   151  				SwIfIndex: ifIdx,
   152  			})
   153  
   154  			if err != nil {
   155  				if test.shouldFail {
   156  					return
   157  				}
   158  				t.Fatalf("create Wireguard tunnel failed: %v\n", err)
   159  			} else {
   160  				if test.shouldFail && test.wgInt2 == nil {
   161  					t.Fatal("create Wireguard tunnel must fail, but it's not")
   162  				}
   163  			}
   164  
   165  			var (
   166  				ifName2 string
   167  				ifIdx2  uint32
   168  			)
   169  			if test.wgInt2 != nil {
   170  				ifName2 := fmt.Sprintf("wg%d-2", i)
   171  				ifIdx2, err = ifHandler.AddWireguardTunnel(ifName2, test.wgInt2)
   172  				ifIndexes.Put(ifName2, &ifaceidx.IfaceMetadata{
   173  					SwIfIndex: ifIdx2,
   174  				})
   175  
   176  				if err != nil {
   177  					if test.shouldFail {
   178  						return
   179  					}
   180  					t.Fatalf("create Wireguard tunnel failed: %v\n", err)
   181  				} else {
   182  					if test.shouldFail {
   183  						t.Fatal("create Wireguard tunnel must fail, but it's not")
   184  					}
   185  				}
   186  			}
   187  
   188  			ifaces, err := ifHandler.DumpInterfaces(ctx.Ctx)
   189  			if err != nil {
   190  				t.Fatalf("dumping interfaces failed: %v", err)
   191  			}
   192  
   193  			t.Logf("DumpInterfaces:\n%v\n", pretty(ifaces))
   194  
   195  			iface, ok := ifaces[ifIdx]
   196  			if !ok {
   197  				t.Fatalf("Wireguard interface was not found in dump")
   198  			}
   199  			if test.wgInt2 != nil {
   200  				_, ok := ifaces[ifIdx2]
   201  				if !ok {
   202  					t.Fatalf("Wireguard interface2 was not found in dump")
   203  				}
   204  			}
   205  
   206  			err = peersTest(&test, ifIndexes, ctx)
   207  			if err != nil {
   208  				t.Fatalf("Peers failed: %v", err)
   209  			}
   210  
   211  			if iface.Interface.GetType() != interfaces.Interface_WIREGUARD_TUNNEL {
   212  				t.Fatalf("Interface is not an Wireguard tunnel")
   213  			}
   214  
   215  			wgLink := iface.Interface.GetWireguard()
   216  			if test.wgInt.SrcAddr != wgLink.SrcAddr {
   217  				t.Fatalf("expected source address <%s>, got: <%s>", test.wgInt.SrcAddr, wgLink.SrcAddr)
   218  			}
   219  
   220  			err = ifHandler.DeleteWireguardTunnel(ifName, ifIdx)
   221  			if err != nil {
   222  				t.Fatalf("delete Wireguard tunnel failed: %v\n", err)
   223  			}
   224  			if test.wgInt2 != nil {
   225  				err = ifHandler.DeleteWireguardTunnel(ifName2, ifIdx2)
   226  				if err != nil {
   227  					t.Fatalf("delete Wireguard tunnel failed: %v\n", err)
   228  				}
   229  			}
   230  
   231  			ifaces, err = ifHandler.DumpInterfaces(ctx.Ctx)
   232  			if err != nil {
   233  				t.Fatalf("dumping interfaces failed: %v", err)
   234  			}
   235  
   236  			if _, ok := ifaces[ifIdx]; ok {
   237  				t.Fatalf("Wireguard interface was found in dump after removing")
   238  			}
   239  			if test.wgInt2 != nil {
   240  				if _, ok := ifaces[ifIdx2]; ok {
   241  					t.Fatalf("Wireguard interface2 was found in dump after removing")
   242  				}
   243  			}
   244  		})
   245  	}
   246  }
   247  
   248  func peersTest(test *testEntry, ifIdx ifaceidx.IfaceMetadataIndex, ctx *TestCtx) (err error) {
   249  	if test.peer == nil {
   250  		return err
   251  	}
   252  
   253  	wgHandler := wgplugin_vppcalls.CompatibleWgVppHandler(ctx.vppClient, ifIdx, logrus.NewLogger("test"))
   254  	if wgHandler == nil {
   255  		return fmt.Errorf("no compatible wireguard handler")
   256  	}
   257  	peerIdx1, err := wgHandler.AddPeer(test.peer)
   258  
   259  	if err != nil {
   260  		if test.shouldFail {
   261  			return
   262  		}
   263  		return err
   264  	} else {
   265  		if test.shouldFail && test.peer2 == nil {
   266  			return fmt.Errorf("create peer must fail, but it's not")
   267  		}
   268  	}
   269  
   270  	var (
   271  		peerIdx2 uint32
   272  	)
   273  	if test.peer2 != nil {
   274  		peerIdx2, err = wgHandler.AddPeer(test.peer2)
   275  
   276  		if err != nil {
   277  			if test.shouldFail {
   278  				return
   279  			}
   280  			return err
   281  		} else {
   282  			if test.shouldFail {
   283  				return fmt.Errorf("create peer must fail, but it's not")
   284  			}
   285  		}
   286  	}
   287  
   288  	peers, err := wgHandler.DumpWgPeers()
   289  	if err != nil {
   290  		return err
   291  	}
   292  	peer := peers[peerIdx1]
   293  
   294  	ctx.t.Logf("DumpWgPeers:\n%+v\n", peers)
   295  
   296  	if test.peer2 != nil {
   297  		if len(peers) != 2 {
   298  			return fmt.Errorf("expected 2 peers in dump, got %d", len(peers))
   299  		}
   300  	} else {
   301  		if len(peers) != 1 {
   302  			return fmt.Errorf("expected 1 peer in dump, got %d", len(peers))
   303  		}
   304  	}
   305  
   306  	if test.peer.PublicKey != peer.PublicKey {
   307  		return fmt.Errorf("expected source address <%s>, got: <%s>", test.peer.PublicKey, peer.PublicKey)
   308  	}
   309  
   310  	err = wgHandler.RemovePeer(peerIdx1)
   311  	if err != nil {
   312  		return fmt.Errorf("delete peer failed: %v\n", err)
   313  	}
   314  	if test.peer2 != nil {
   315  		err = wgHandler.RemovePeer(peerIdx2)
   316  		if err != nil {
   317  			return fmt.Errorf("delete peer failed: %v\n", err)
   318  		}
   319  	}
   320  
   321  	peers, err = wgHandler.DumpWgPeers()
   322  	if err != nil {
   323  		return err
   324  	}
   325  
   326  	if len(peers) != 0 {
   327  		return fmt.Errorf("expected 0 peers in dump, got %d", len(peers))
   328  	}
   329  
   330  	return
   331  }