go.ligato.io/vpp-agent/v3@v3.5.0/plugins/restapi/plugin_restapi.go (about)

     1  //  Copyright (c) 2018 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 restapi
    16  
    17  import (
    18  	"fmt"
    19  	"net/http"
    20  	"sync"
    21  
    22  	"go.ligato.io/cn-infra/v2/infra"
    23  	"go.ligato.io/cn-infra/v2/rpc/rest"
    24  	access "go.ligato.io/cn-infra/v2/rpc/rest/security/model/access-security"
    25  	"go.ligato.io/cn-infra/v2/servicelabel"
    26  	"go.ligato.io/vpp-agent/v3/plugins/govppmux"
    27  	vpevppcalls "go.ligato.io/vpp-agent/v3/plugins/govppmux/vppcalls"
    28  	kvscheduler "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    29  	linuxifplugin "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin"
    30  	iflinuxcalls "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/linuxcalls"
    31  	l3linuxcalls "go.ligato.io/vpp-agent/v3/plugins/linux/l3plugin/linuxcalls"
    32  	"go.ligato.io/vpp-agent/v3/plugins/linux/nsplugin"
    33  	"go.ligato.io/vpp-agent/v3/plugins/netalloc"
    34  	"go.ligato.io/vpp-agent/v3/plugins/orchestrator"
    35  	"go.ligato.io/vpp-agent/v3/plugins/restapi/resturl"
    36  	telemetryvppcalls "go.ligato.io/vpp-agent/v3/plugins/telemetry/vppcalls"
    37  	abfvppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/abfplugin/vppcalls"
    38  	"go.ligato.io/vpp-agent/v3/plugins/vpp/aclplugin"
    39  	aclvppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/aclplugin/vppcalls"
    40  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin"
    41  	ifvppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls"
    42  	ipsecvppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/ipsecplugin/vppcalls"
    43  	"go.ligato.io/vpp-agent/v3/plugins/vpp/l2plugin"
    44  	l2vppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/l2plugin/vppcalls"
    45  	"go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin"
    46  	l3vppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vppcalls"
    47  	natvppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/natplugin/vppcalls"
    48  	puntvppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/puntplugin/vppcalls"
    49  	wireguardvppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/wireguardplugin/vppcalls"
    50  )
    51  
    52  // REST api methods
    53  const (
    54  	GET  = http.MethodGet
    55  	POST = http.MethodPost
    56  	PUT  = http.MethodPut
    57  )
    58  
    59  // Default Go routine count used to retrieve linux configuration
    60  const defaultGoRoutineCount = 10
    61  
    62  // Plugin registers Rest Plugin
    63  type Plugin struct {
    64  	Deps
    65  
    66  	// Index page
    67  	index *index
    68  
    69  	// Handlers
    70  	vpeHandler  vpevppcalls.VppCoreAPI
    71  	teleHandler telemetryvppcalls.TelemetryVppAPI
    72  	// VPP Handlers
    73  	abfHandler       abfvppcalls.ABFVppRead
    74  	aclHandler       aclvppcalls.ACLVppRead
    75  	ifHandler        ifvppcalls.InterfaceVppRead
    76  	natHandler       natvppcalls.NatVppRead
    77  	l2Handler        l2vppcalls.L2VppAPI
    78  	l3Handler        l3vppcalls.L3VppAPI
    79  	ipSecHandler     ipsecvppcalls.IPSecVPPRead
    80  	puntHandler      puntvppcalls.PuntVPPRead
    81  	wireguardHandler wireguardvppcalls.WgVppRead
    82  	// Linux handlers
    83  	linuxIfHandler iflinuxcalls.NetlinkAPIRead
    84  	linuxL3Handler l3linuxcalls.NetlinkAPIRead
    85  
    86  	govppmux sync.Mutex
    87  }
    88  
    89  // Deps represents dependencies of Rest Plugin
    90  type Deps struct {
    91  	infra.PluginDeps
    92  	HTTPHandlers  rest.HTTPHandlers
    93  	VPP           govppmux.API
    94  	ServiceLabel  servicelabel.ReaderAPI
    95  	AddrAlloc     netalloc.AddressAllocator
    96  	VPPACLPlugin  aclplugin.API
    97  	VPPIfPlugin   ifplugin.API
    98  	VPPL2Plugin   *l2plugin.L2Plugin
    99  	VPPL3Plugin   *l3plugin.L3Plugin
   100  	LinuxIfPlugin linuxifplugin.API
   101  	NsPlugin      nsplugin.API
   102  	Dispatcher    orchestrator.Dispatcher
   103  	KVScheduler   kvscheduler.KVScheduler
   104  }
   105  
   106  // index defines map of main index page entries
   107  type index struct {
   108  	ItemMap map[string][]indexItem
   109  }
   110  
   111  // indexItem is single index page entry
   112  type indexItem struct {
   113  	Name string
   114  	Path string
   115  }
   116  
   117  // Init initializes the Rest Plugin
   118  func (p *Plugin) Init() (err error) {
   119  	// VPP Indexes
   120  	ifIndexes := p.VPPIfPlugin.GetInterfaceIndex()
   121  	bdIndexes := p.VPPL2Plugin.GetBDIndex()
   122  	dhcpIndexes := p.VPPIfPlugin.GetDHCPIndex()
   123  	aclIndexes := p.VPPACLPlugin.GetACLIndex() // TODO: make ACL optional
   124  	vrfIndexes := p.VPPL3Plugin.GetVRFIndex()
   125  
   126  	// Linux Indexes
   127  	linuxIfIndexes := p.LinuxIfPlugin.GetInterfaceIndex()
   128  
   129  	// Initialize VPP handlers
   130  	p.vpeHandler, err = vpevppcalls.NewHandler(p.VPP)
   131  	if err != nil {
   132  		return fmt.Errorf("VPP core handler error: %w", err)
   133  	} else if p.vpeHandler == nil {
   134  		p.Log.Info("VPP core handler is not available, it will be skipped")
   135  	}
   136  	p.teleHandler = telemetryvppcalls.CompatibleTelemetryHandler(p.VPP)
   137  	if p.teleHandler == nil {
   138  		p.Log.Info("VPP Telemetry handler is not available, it will be skipped")
   139  	}
   140  
   141  	// core
   142  	p.ifHandler = ifvppcalls.CompatibleInterfaceVppHandler(p.VPP, p.Log)
   143  	if p.ifHandler == nil {
   144  		p.Log.Info("VPP Interface handler is not available, it will be skipped")
   145  	}
   146  	p.l2Handler = l2vppcalls.CompatibleL2VppHandler(p.VPP, ifIndexes, bdIndexes, p.Log)
   147  	if p.l2Handler == nil {
   148  		p.Log.Info("VPP L2 handler is not available, it will be skipped")
   149  	}
   150  	p.l3Handler = l3vppcalls.CompatibleL3VppHandler(p.VPP, ifIndexes, vrfIndexes, p.AddrAlloc, p.Log)
   151  	if p.l3Handler == nil {
   152  		p.Log.Info("VPP L3 handler is not available, it will be skipped")
   153  	}
   154  	p.ipSecHandler = ipsecvppcalls.CompatibleIPSecVppHandler(p.VPP, ifIndexes, p.Log)
   155  	if p.ipSecHandler == nil {
   156  		p.Log.Info("VPP IPSec handler is not available, it will be skipped")
   157  	}
   158  
   159  	// plugins (might not be available - disabled)
   160  	p.abfHandler = abfvppcalls.CompatibleABFHandler(p.VPP, aclIndexes, ifIndexes, p.Log)
   161  	if p.abfHandler == nil {
   162  		p.Log.Infof("ABF handler is not available, it will be skipped")
   163  	}
   164  	p.aclHandler = aclvppcalls.CompatibleACLHandler(p.VPP, ifIndexes)
   165  	if p.aclHandler == nil {
   166  		p.Log.Infof("ACL handler is not available, it will be skipped")
   167  	}
   168  	p.natHandler = natvppcalls.CompatibleNatVppHandler(p.VPP, ifIndexes, dhcpIndexes, p.Log)
   169  	if p.natHandler == nil {
   170  		p.Log.Infof("NAT handler is not available, it will be skipped")
   171  	}
   172  	p.puntHandler = puntvppcalls.CompatiblePuntVppHandler(p.VPP, ifIndexes, p.Log)
   173  	if p.puntHandler == nil {
   174  		p.Log.Infof("Punt handler is not available, it will be skipped")
   175  	}
   176  	p.wireguardHandler = wireguardvppcalls.CompatibleWgVppHandler(p.VPP, ifIndexes, p.Log)
   177  	if p.wireguardHandler == nil {
   178  		p.Log.Info("Wireguard handler is not available, it will be skipped")
   179  	}
   180  
   181  	// Linux handlers
   182  	p.linuxIfHandler = iflinuxcalls.NewNetLinkHandler(p.NsPlugin, linuxIfIndexes, p.ServiceLabel.GetAgentPrefix(),
   183  		defaultGoRoutineCount, p.Log)
   184  	p.linuxL3Handler = l3linuxcalls.NewNetLinkHandler(p.NsPlugin, linuxIfIndexes, defaultGoRoutineCount, p.Log)
   185  
   186  	p.index = &index{
   187  		ItemMap: getIndexPageItems(),
   188  	}
   189  
   190  	// Register permission groups, used if REST security is enabled
   191  	p.HTTPHandlers.RegisterPermissionGroup(getPermissionsGroups()...)
   192  
   193  	return nil
   194  }
   195  
   196  // AfterInit is used to register HTTP handlers
   197  func (p *Plugin) AfterInit() (err error) {
   198  	// Info handlers.
   199  	p.registerInfoHandlers()
   200  	// NB configuration handlers.
   201  	p.registerNBConfigurationHandlers()
   202  	// VPP handlers
   203  	p.registerTelemetryHandlers()
   204  	// core
   205  	p.registerInterfaceHandlers()
   206  	p.registerL2Handlers()
   207  	p.registerL3Handlers()
   208  	p.registerIPSecHandlers()
   209  	// plugins
   210  	p.registerABFHandler()
   211  	p.registerACLHandlers()
   212  	p.registerNATHandlers()
   213  	p.registerPuntHandlers()
   214  	// Linux handlers
   215  	p.registerLinuxInterfaceHandlers()
   216  	p.registerLinuxL3Handlers()
   217  	// Index and stats handlers
   218  	p.registerIndexHandlers()
   219  	p.registerStatsHandler()
   220  	return nil
   221  }
   222  
   223  // Close is used to clean up resources used by Plugin
   224  func (p *Plugin) Close() error {
   225  	return nil
   226  }
   227  
   228  // Fill index item lists
   229  func getIndexPageItems() map[string][]indexItem {
   230  	idxMap := map[string][]indexItem{
   231  		"Info": {
   232  			{Name: "Version", Path: resturl.Version},
   233  			{Name: "JSONSchema", Path: resturl.JSONSchema},
   234  		},
   235  		"NB configuration": {
   236  			{Name: "Get or Put NB configuration", Path: resturl.Configuration},
   237  			{Name: "Validation", Path: resturl.Validate},
   238  		},
   239  		"ACL plugin": {
   240  			{Name: "IP-type access lists", Path: resturl.ACLIP},
   241  			{Name: "MACIP-type access lists", Path: resturl.ACLMACIP},
   242  		},
   243  		"Interface plugin": {
   244  			{Name: "All interfaces", Path: resturl.Interface},
   245  			{Name: "Loopbacks", Path: resturl.Loopback},
   246  			{Name: "Ethernets", Path: resturl.Ethernet},
   247  			{Name: "Memifs", Path: resturl.Memif},
   248  			{Name: "Taps", Path: resturl.Tap},
   249  			{Name: "VxLANs", Path: resturl.VxLan},
   250  			{Name: "Af-packets", Path: resturl.AfPacket},
   251  		},
   252  		"L2 plugin": {
   253  			{Name: "Bridge domains", Path: resturl.Bd},
   254  			{Name: "L2Fibs", Path: resturl.Fib},
   255  			{Name: "Cross connects", Path: resturl.Xc},
   256  		},
   257  		"L3 plugin": {
   258  			{Name: "Routes", Path: resturl.Routes},
   259  			{Name: "ARPs", Path: resturl.Arps},
   260  			{Name: "Proxy ARP interfaces", Path: resturl.PArpIfs},
   261  			{Name: "Proxy ARP ranges", Path: resturl.PArpRngs},
   262  		},
   263  		"Telemetry": {
   264  			{Name: "All data", Path: resturl.Telemetry},
   265  			{Name: "Memory", Path: resturl.TMemory},
   266  			{Name: "Runtime", Path: resturl.TRuntime},
   267  			{Name: "Node count", Path: resturl.TNodeCount},
   268  		},
   269  		"Stats": {
   270  			{Name: "Configurator Stats", Path: resturl.ConfiguratorStats},
   271  		},
   272  	}
   273  	return idxMap
   274  }
   275  
   276  // Create permission groups (tracer, telemetry, dump - optionally add more in the future). Used only if
   277  // REST security is enabled in plugin
   278  func getPermissionsGroups() []*access.PermissionGroup {
   279  	infoPg := &access.PermissionGroup{
   280  		Name: "info",
   281  		Permissions: []*access.PermissionGroup_Permissions{
   282  			newPermission("/", GET),
   283  			newPermission(resturl.Version, GET),
   284  			newPermission(resturl.JSONSchema, GET),
   285  		},
   286  	}
   287  	nbConfigValidationPg := &access.PermissionGroup{
   288  		Name: "nbConfigValidation",
   289  		Permissions: []*access.PermissionGroup_Permissions{
   290  			newPermission("/", GET),
   291  			newPermission(resturl.Validate, GET),
   292  		},
   293  	}
   294  	nbConfigReadPg := &access.PermissionGroup{
   295  		Name: "nbConfigRead",
   296  		Permissions: []*access.PermissionGroup_Permissions{
   297  			newPermission("/", GET),
   298  			newPermission(resturl.Configuration, GET),
   299  		},
   300  	}
   301  	nbConfigWritePg := &access.PermissionGroup{
   302  		Name: "nbConfigWrite",
   303  		Permissions: []*access.PermissionGroup_Permissions{
   304  			newPermission("/", PUT),
   305  			newPermission(resturl.Configuration, PUT),
   306  		},
   307  	}
   308  	tracerPg := &access.PermissionGroup{
   309  		Name: "stats",
   310  		Permissions: []*access.PermissionGroup_Permissions{
   311  			newPermission("/", GET),
   312  			newPermission(resturl.ConfiguratorStats, GET),
   313  		},
   314  	}
   315  	telemetryPg := &access.PermissionGroup{
   316  		Name: "telemetry",
   317  		Permissions: []*access.PermissionGroup_Permissions{
   318  			newPermission("/", GET),
   319  			newPermission(resturl.Telemetry, GET),
   320  			newPermission(resturl.TMemory, GET),
   321  			newPermission(resturl.TRuntime, GET),
   322  			newPermission(resturl.TNodeCount, GET),
   323  		},
   324  	}
   325  	dumpPg := &access.PermissionGroup{
   326  		Name: "dump",
   327  		Permissions: []*access.PermissionGroup_Permissions{
   328  			newPermission("/", GET),
   329  			newPermission(resturl.ABF, GET),
   330  			newPermission(resturl.ACLIP, GET),
   331  			newPermission(resturl.ACLMACIP, GET),
   332  			newPermission(resturl.Interface, GET),
   333  			newPermission(resturl.Loopback, GET),
   334  			newPermission(resturl.Ethernet, GET),
   335  			newPermission(resturl.Memif, GET),
   336  			newPermission(resturl.Tap, GET),
   337  			newPermission(resturl.VxLan, GET),
   338  			newPermission(resturl.AfPacket, GET),
   339  			newPermission(resturl.Bd, GET),
   340  			newPermission(resturl.Fib, GET),
   341  			newPermission(resturl.Xc, GET),
   342  			newPermission(resturl.Arps, GET),
   343  			newPermission(resturl.Routes, GET),
   344  			newPermission(resturl.PArpIfs, GET),
   345  			newPermission(resturl.PArpRngs, GET),
   346  		},
   347  	}
   348  
   349  	return []*access.PermissionGroup{infoPg, tracerPg, telemetryPg, dumpPg,
   350  		nbConfigValidationPg, nbConfigReadPg, nbConfigWritePg}
   351  }
   352  
   353  // Returns permission object with url and provided methods
   354  func newPermission(url string, methods ...string) *access.PermissionGroup_Permissions {
   355  	return &access.PermissionGroup_Permissions{
   356  		Url:            url,
   357  		AllowedMethods: methods,
   358  	}
   359  }