summaryrefslogtreecommitdiffstats
path: root/src/vnet/ipsec
diff options
context:
space:
mode:
authorMatthew Smith <mgsmith@netgate.com>2017-05-14 21:47:18 -0500
committerNeale Ranns <nranns@cisco.com>2017-05-15 20:49:05 +0000
commite04d09de8433213f3c3e8cdc5acaa7e2289d92de (patch)
tree17e444800a9fb647d1a5490e6d5cd84da86b1051 /src/vnet/ipsec
parent5c85f358bb08403d9edce14d9cc63675bda6799d (diff)
Add sw_if_index of tunnel interface to API reply for ipsec_tunnel_if_add_del
Change-Id: If5158f6fa7344dee94548c93dace779430e0647f Signed-off-by: Matthew Smith <mgsmith@netgate.com>
Diffstat (limited to 'src/vnet/ipsec')
-rw-r--r--src/vnet/ipsec/ipsec.api13
-rw-r--r--src/vnet/ipsec/ipsec.h4
-rw-r--r--src/vnet/ipsec/ipsec_api.c12
-rw-r--r--src/vnet/ipsec/ipsec_if.c22
4 files changed, 36 insertions, 15 deletions
diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api
index f3b5993700b..011b0d4b1ff 100644
--- a/src/vnet/ipsec/ipsec.api
+++ b/src/vnet/ipsec/ipsec.api
@@ -511,7 +511,7 @@ define ipsec_spd_details {
@param remote_integ_key_len - length of remote integrity key in bytes
@param remote_integ_key - integrity key for inbound IPsec SA
*/
-autoreply define ipsec_tunnel_if_add_del {
+define ipsec_tunnel_if_add_del {
u32 client_index;
u32 context;
u8 is_add;
@@ -533,6 +533,17 @@ autoreply define ipsec_tunnel_if_add_del {
u8 remote_integ_key[128];
};
+/** \brief Add/delete IPsec tunnel interface response
+ @param context - sender context, to match reply w/ request
+ @param retval - return status
+ @param sw_if_index - sw_if_index of new interface (for successful add)
+*/
+define ipsec_tunnel_if_add_del_reply {
+ u32 context;
+ i32 retval;
+ u32 sw_if_index;
+};
+
/*
* Local Variables:
* eval: (c-set-style "gnu")
diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h
index c884e360004..1eff1c3a0be 100644
--- a/src/vnet/ipsec/ipsec.h
+++ b/src/vnet/ipsec/ipsec.h
@@ -308,7 +308,9 @@ uword unformat_ipsec_policy_action (unformat_input_t * input, va_list * args);
uword unformat_ipsec_crypto_alg (unformat_input_t * input, va_list * args);
uword unformat_ipsec_integ_alg (unformat_input_t * input, va_list * args);
-/*u32 ipsec_add_del_tunnel_if (vnet_main_t * vnm, ipsec_add_del_tunnel_args_t * args); */
+int ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
+ ipsec_add_del_tunnel_args_t * args,
+ u32 * sw_if_index);
int ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args);
int ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
ipsec_add_del_ipsec_gre_tunnel_args_t *
diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c
index 04dff4d0fd0..3a5b89feb7d 100644
--- a/src/vnet/ipsec/ipsec_api.c
+++ b/src/vnet/ipsec/ipsec_api.c
@@ -357,6 +357,9 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
mp)
{
vl_api_ipsec_tunnel_if_add_del_reply_t *rmp;
+ ipsec_main_t *im = &ipsec_main;
+ vnet_main_t *vnm = im->vnet_main;
+ u32 sw_if_index = ~0;
int rv;
#if WITH_LIBSSL > 0
@@ -386,15 +389,20 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
memcpy (&tun.remote_integ_key, &mp->remote_integ_key,
mp->remote_integ_key_len);
- rv = ipsec_add_del_tunnel_if (&tun);
+ rv = ipsec_add_del_tunnel_if_internal (vnm, &tun, &sw_if_index);
#else
rv = VNET_API_ERROR_UNIMPLEMENTED;
#endif
- REPLY_MACRO (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY);
+ REPLY_MACRO2 (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY, (
+ {
+ rmp->sw_if_index =
+ htonl (sw_if_index);
+ }));
}
+
static void
vl_api_ikev2_profile_add_del_t_handler (vl_api_ikev2_profile_add_del_t * mp)
{
diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c
index ed1248942e3..9b0eb5b2779 100644
--- a/src/vnet/ipsec/ipsec_if.c
+++ b/src/vnet/ipsec/ipsec_if.c
@@ -92,16 +92,12 @@ VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
/* *INDENT-ON* */
static int
-ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
- ipsec_add_del_tunnel_args_t * args);
-
-static int
ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a)
{
vnet_main_t *vnm = vnet_get_main ();
ASSERT (vlib_get_thread_index () == 0);
- return ipsec_add_del_tunnel_if_internal (vnm, a);
+ return ipsec_add_del_tunnel_if_internal (vnm, a, NULL);
}
int
@@ -114,11 +110,12 @@ ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
int
ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
- ipsec_add_del_tunnel_args_t * args)
+ ipsec_add_del_tunnel_args_t * args,
+ u32 * sw_if_index)
{
ipsec_tunnel_if_t *t;
ipsec_main_t *im = &ipsec_main;
- vnet_hw_interface_t *hi;
+ vnet_hw_interface_t *hi = NULL;
u32 hw_if_index = ~0;
uword *p;
ipsec_sa_t *sa;
@@ -209,10 +206,10 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
t - im->tunnel_interfaces,
ipsec_hw_class.index,
t - im->tunnel_interfaces);
-
- hi = vnet_get_hw_interface (vnm, hw_if_index);
- hi->output_node_index = ipsec_if_output_node.index;
}
+
+ hi = vnet_get_hw_interface (vnm, hw_if_index);
+ hi->output_node_index = ipsec_if_output_node.index;
t->hw_if_index = hw_if_index;
/*1st interface, register protocol */
@@ -220,7 +217,6 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
ipsec_if_input_node.index);
- return hw_if_index;
}
else
{
@@ -253,6 +249,10 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
hash_unset (im->ipsec_if_pool_index_by_key, key);
pool_put (im->tunnel_interfaces, t);
}
+
+ if (sw_if_index)
+ *sw_if_index = hi->sw_if_index;
+
return 0;
}
ing.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/*
 * Copyright (c) 2021 Cisco Systems and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*Go-FUSE allows us to define the behaviour of our filesystem by recoding any primitive function we need.
 *The structure of the filesystem is constructed as a tree.
 *Each type of nodes (root, directory, file) follows its own prmitives.
 */
package main

import (
	"context"
	"fmt"
	"path"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/hanwen/go-fuse/v2/fs"
	"github.com/hanwen/go-fuse/v2/fuse"

	"git.fd.io/govpp.git/adapter"
	"git.fd.io/govpp.git/adapter/statsclient"
)

func updateDir(ctx context.Context, n *fs.Inode, cl *statsclient.StatsClient, dirPath string) syscall.Errno {
	stats, err := cl.PrepareDir(dirPath)
	if err != nil {
		LogMsg(fmt.Sprintf("Listing stats index failed: %v\n", err))
		return syscall.EAGAIN
	}

	n.Operations().(*dirNode).epoch = stats.Epoch

	n.RmAllChildren()

	for _, entry := range stats.Entries {
		localPath := strings.TrimPrefix(string(entry.Name), dirPath)
		dirPath, base := filepath.Split(localPath)

		parent := n
		for _, component := range strings.Split(dirPath, "/") {
			if len(component) == 0 {
				continue
			}
			child := parent.GetChild(component)
			if child == nil {
				child = parent.NewInode(ctx, &dirNode{client: cl, epoch: stats.Epoch},
					fs.StableAttr{Mode: fuse.S_IFDIR})
				parent.AddChild(component, child, true)
			} else {
				child.Operations().(*dirNode).epoch = stats.Epoch
			}

			parent = child
		}

		filename := strings.Replace(base, " ", "_", -1)
		child := parent.GetChild(filename)
		if child == nil {
			child := parent.NewPersistentInode(ctx, &statNode{client: cl, index: entry.Index}, fs.StableAttr{})
			parent.AddChild(filename, child, true)
		}
	}
	return 0
}

func getCounterContent(index uint32, client *statsclient.StatsClient) (content string, status syscall.Errno) {
	content = ""
	statsDir, err := client.PrepareDirOnIndex(index)
	if err != nil {
		LogMsg(fmt.Sprintf("Dumping stats on index failed: %v\n", err))
		return content, syscall.EAGAIN
	}
	if len(statsDir.Entries) != 1 {
		return content, syscall.ENOENT
	}
	result := statsDir.Entries[0]
	if result.Data == nil {
		return content, 0
	}

	switch result.Type {
	case adapter.ScalarIndex:
		stats := result.Data.(adapter.ScalarStat)
		content = fmt.Sprintf("%.2f\n", stats)
	case adapter.ErrorIndex:
		stats := result.Data.(adapter.ErrorStat)
		content = fmt.Sprintf("%-16s%s\n", "Index", "Count")
		for i, value := range stats {
			content += fmt.Sprintf("%-16d%d\n", i, value)
		}
	case adapter.SimpleCounterVector:
		stats := result.Data.(adapter.SimpleCounterStat)
		content = fmt.Sprintf("%-16s%-16s%s\n", "Thread", "Index", "Packets")
		for i, vector := range stats {
			for j, value := range vector {
				content += fmt.Sprintf("%-16d%-16d%d\n", i, j, value)
			}
		}
	case adapter.CombinedCounterVector:
		stats := result.Data.(adapter.CombinedCounterStat)
		content = fmt.Sprintf("%-16s%-16s%-16s%s\n", "Thread", "Index", "Packets", "Bytes")
		for i, vector := range stats {
			for j, value := range vector {
				content += fmt.Sprintf("%-16d%-16d%-16d%d\n", i, j, value[0], value[1])
			}
		}
	case adapter.NameVector:
		stats := result.Data.(adapter.NameStat)
		content = fmt.Sprintf("%-16s%s\n", "Index", "Name")
		for i, value := range stats {
			content += fmt.Sprintf("%-16d%s\n", i, string(value))
		}
	default:
		content = fmt.Sprintf("Unknown stat type: %d\n", result.Type)
		//For now, the empty type (file deleted) is not implemented in GoVPP
		return content, syscall.ENOENT
	}
	return content, fs.OK
}

//The dirNode structure represents directories
type dirNode struct {
	fs.Inode
	client *statsclient.StatsClient
	epoch  int64
}

var _ = (fs.NodeOpendirer)((*dirNode)(nil))
var _ = (fs.NodeGetattrer)((*dirNode)(nil))
var _ = (fs.NodeOnAdder)((*dirNode)(nil))

func (dn *dirNode) OnAdd(ctx context.Context) {
	if dn.Inode.IsRoot() {
		updateDir(ctx, &dn.Inode, dn.client, "/")
	}
}

func (dn *dirNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
	out.Mtime = uint64(time.Now().Unix())
	out.Atime = out.Mtime
	out.Ctime = out.Mtime
	return 0
}

func (dn *dirNode) Opendir(ctx context.Context) syscall.Errno {
	var status syscall.Errno = syscall.F_OK
	var sleepTime time.Duration = 10 * time.Millisecond
	newEpoch, inProgress := dn.client.GetEpoch()
	for inProgress {
		newEpoch, inProgress = dn.client.GetEpoch()
		time.Sleep(sleepTime)
		sleepTime = sleepTime * 2
	}

	//We check that the directory epoch is up to date
	if dn.epoch != newEpoch {
		//directoryPath is the path to the current directory from root
		directoryPath := path.Clean("/" + dn.Inode.Path(nil) + "/")
		status = updateDir(ctx, &dn.Inode, dn.client, directoryPath)
	}
	return status
}

//The statNode structure represents counters
type statNode struct {
	fs.Inode
	client *statsclient.StatsClient
	index  uint32
}

var _ = (fs.NodeOpener)((*statNode)(nil))
var _ = (fs.NodeGetattrer)((*statNode)(nil))

func (fh *statNode) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
	out.Mtime = uint64(time.Now().Unix())
	out.Atime = out.Mtime
	out.Ctime = out.Mtime
	return 0
}

//When a file is opened, the correpsonding counter value is dumped and a file handle is created
func (sn *statNode) Open(ctx context.Context, flags uint32) (fs.FileHandle, uint32, syscall.Errno) {
	content, status := getCounterContent(sn.index, sn.client)
	if status == syscall.ENOENT {
		_, parent := sn.Inode.Parent()
		parent.RmChild(sn.Inode.Path(parent))

	}
	return &statFH{data: []byte(content)}, fuse.FOPEN_DIRECT_IO, status
}

/* The statFH structure aims at dislaying the counters dynamically.
 * It allows the Kernel to read data as I/O without having to specify files sizes, as they may evolve dynamically.
 */
type statFH struct {
	data []byte
}

var _ = (fs.FileReader)((*statFH)(nil))

func (fh *statFH) Read(ctx context.Context, data []byte, off int64) (fuse.ReadResult, syscall.Errno) {
	end := int(off) + len(data)
	if end > len(fh.data) {
		end = len(fh.data)
	}
	return fuse.ReadResultData(fh.data[off:end]), fs.OK
}

//NewStatsFileSystem creates the fs for the stat segment.
func NewStatsFileSystem(sc *statsclient.StatsClient) (root fs.InodeEmbedder, err error) {
	return &dirNode{client: sc}, nil
}