Skip to content

Commit

Permalink
cnf:network-add-nftables-test-cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Gregory Kopels committed Jan 27, 2025
1 parent 6ae6ebb commit 5ffcef2
Show file tree
Hide file tree
Showing 17 changed files with 804 additions and 221 deletions.
25 changes: 25 additions & 0 deletions tests/cnf/core/network/internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/golang/glog"
"github.com/openshift-kni/eco-goinfra/pkg/pod"
"github.com/openshift-kni/eco-gotests/tests/cnf/core/network/internal/ipaddr"
. "github.com/openshift-kni/eco-gotests/tests/cnf/core/network/internal/netinittools"
"github.com/openshift-kni/eco-gotests/tests/cnf/core/network/internal/netparam"
)
Expand Down Expand Up @@ -114,6 +115,21 @@ func RxTrafficOnClientPod(clientPod *pod.Builder, clientRxCmd string) error {
return nil
}

// ValidateTCPTraffic runs the testcmd with tcp and specified interface, port and destination.
// The receiving client needs to be listening to the specified port.
func ValidateTCPTraffic(clientPod *pod.Builder, destIPAddrs []string, interfaceName,
containerName string, portNum int) error {
for _, destIPAddr := range removePrefixFromIPList(destIPAddrs) {
command := fmt.Sprintf("testcmd -interface %s -protocol tcp -port %d -server %s", interfaceName,
portNum, destIPAddr)
_, err := clientPod.ExecCommand([]string{"bash", "-c", command}, containerName)

return err
}

return nil
}

// checkRxOnly checks the number of incoming packets.
func checkRxOnly(out string) bool {
lines := strings.Split(out, "\n")
Expand Down Expand Up @@ -160,3 +176,12 @@ func getNumberOfPackets(line, firstFieldSubstr string) int {

return numberOfPackets
}

func removePrefixFromIPList(ipAddressList []string) []string {
var ipAddressListWithoutPrefix []string
for _, ipaddress := range ipAddressList {
ipAddressListWithoutPrefix = append(ipAddressListWithoutPrefix, ipaddr.RemovePrefix(ipaddress))
}

return ipAddressListWithoutPrefix
}
21 changes: 17 additions & 4 deletions tests/cnf/core/network/internal/define/nad.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"github.com/golang/glog"
"github.com/openshift-kni/eco-goinfra/pkg/clients"
"github.com/openshift-kni/eco-goinfra/pkg/nad"
"github.com/openshift-kni/eco-goinfra/pkg/pod"
"gopkg.in/k8snetworkplumbingwg/multus-cni.v4/pkg/types"
)

// MasterNadPlugin sets NetworkAttachmentDefinition master plugin based on given input.
Expand Down Expand Up @@ -54,7 +56,7 @@ func MacVlanNad(apiClient *clients.Settings, name, nsName, intName string, ipam
return nil, err
}

return createNadWithMasterPlugin(apiClient, name, nsName, masterPlugin)
return CreateNadWithMasterPlugin(apiClient, name, nsName, masterPlugin)
}

// VlanNad defines and creates Vlan NetworkAttachmentDefinition on a cluster.
Expand All @@ -67,7 +69,7 @@ func VlanNad(
return nil, err
}

return createNadWithMasterPlugin(apiClient, name, nsName, masterPlugin)
return CreateNadWithMasterPlugin(apiClient, name, nsName, masterPlugin)
}

// IPVlanNad defines and creates IP-Vlan NetworkAttachmentDefinition on a cluster.
Expand All @@ -78,10 +80,11 @@ func IPVlanNad(apiClient *clients.Settings, name, nsName, intName string, ipam *
return nil, err
}

return createNadWithMasterPlugin(apiClient, name, nsName, masterPlugin)
return CreateNadWithMasterPlugin(apiClient, name, nsName, masterPlugin)
}

func createNadWithMasterPlugin(
// CreateNadWithMasterPlugin creates a MasterPlugin network attachment definition.
func CreateNadWithMasterPlugin(
apiClient *clients.Settings, name, nsName string, masterPlugin *nad.MasterPlugin) (*nad.Builder, error) {
createdNad, err := nad.NewBuilder(apiClient, name, nsName).WithMasterPlugin(masterPlugin).Create()
if err != nil {
Expand All @@ -90,3 +93,13 @@ func createNadWithMasterPlugin(

return createdNad, nil
}

// CreateStaticIPAnnotations creates a static ip annotation used together with the nad in a pod for IP configuration.
func CreateStaticIPAnnotations(internalNADName, externalNADName string, internalIPAddresses,
externalIPAddresses []string) []*types.NetworkSelectionElement {
ipAnnotation := pod.StaticIPAnnotation(internalNADName, internalIPAddresses)
ipAnnotation = append(ipAnnotation,
pod.StaticIPAnnotation(externalNADName, externalIPAddresses)...)

return ipAnnotation
}
90 changes: 90 additions & 0 deletions tests/cnf/core/network/internal/frrconfig/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package frrconfig

const (
// ContainerName is the container name running in the frr pod.
ContainerName = "frr"
// DaemonsFile represents FRR default daemon configuration template.
DaemonsFile = `
# This file tells the frr package which daemons to start.
#
# Sample configurations for these daemons can be found in
# /usr/share/doc/frr/examples/.
#
# ATTENTION:
#
# When activating a daemon for the first time, a config file, even if it is
# empty, has to be present *and* be owned by the user and group "frr", else
# the daemon will not be started by /etc/init.d/frr. The permissions should
# be u=rw,g=r,o=.
# When using "vtysh" such a config file is also needed. It should be owned by
# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
#
# The watchfrr, zebra and staticd daemons are always started.
#
bgpd=yes
ospfd=no
ospf6d=no
ripd=no
ripngd=no
isisd=no
pimd=no
ldpd=no
nhrpd=no
eigrpd=no
babeld=no
sharpd=no
pbrd=no
bfdd=yes
fabricd=no
vrrpd=no
pathd=no
#
# If this option is set the /etc/init.d/frr script automatically loads
# the config via "vtysh -b" when the servers are started.
# Check /etc/pam.d/frr if you intend to use "vtysh"!
#
vtysh_enable=yes
zebra_options=" -A 127.0.0.1 -s 90000000"
bgpd_options=" -A 127.0.0.1"
ospfd_options=" -A 127.0.0.1"
ospf6d_options=" -A ::1"
ripd_options=" -A 127.0.0.1"
ripngd_options=" -A ::1"
isisd_options=" -A 127.0.0.1"
pimd_options=" -A 127.0.0.1"
ldpd_options=" -A 127.0.0.1"
nhrpd_options=" -A 127.0.0.1"
eigrpd_options=" -A 127.0.0.1"
babeld_options=" -A 127.0.0.1"
sharpd_options=" -A 127.0.0.1"
pbrd_options=" -A 127.0.0.1"
staticd_options="-A 127.0.0.1"
bfdd_options=" -A 127.0.0.1"
fabricd_options="-A 127.0.0.1"
vrrpd_options=" -A 127.0.0.1"
pathd_options=" -A 127.0.0.1"
# configuration profile
#
#frr_profile="traditional"
#frr_profile="datacenter"
#
# This is the maximum number of FD's that will be available.
# Upon startup this is read by the control files and ulimit
# is called. Uncomment and use a reasonable value for your
# setup if you are expecting a large number of peers in
# say BGP.
#MAX_FDS=1024
# The list of daemons to watch is automatically generated by the init script.
#watchfrr_options=""
# To make watchfrr create/join the specified netns, use the following option:
#watchfrr_options="--netns"
# This only has an effect in /etc/frr/<somename>/daemons, and you need to
# start FRR with "/usr/lib/frr/frrinit.sh start <somename>".
# for debugging purposes, you can specify a "wrap" command to start instead
# of starting the daemon directly, e.g. to use valgrind on ospfd:
# ospfd_wrap="/usr/bin/valgrind"
# or you can use "all_wrap" for all daemons, e.g. to use perf record:
# all_wrap="/usr/bin/perf record --call-graph -"
# the normal daemon command is added to this at the end.
`
)
89 changes: 89 additions & 0 deletions tests/cnf/core/network/internal/frrconfig/frrconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package frrconfig

import (
"fmt"
"strings"

"github.com/golang/glog"
"github.com/openshift-kni/eco-goinfra/pkg/nodes"
"github.com/openshift-kni/eco-goinfra/pkg/pod"
"github.com/openshift-kni/eco-gotests/tests/cnf/core/network/internal/ipaddr"
)

// SetStaticRoute could set or delete static route on all Speaker pods.
func SetStaticRoute(frrPod *pod.Builder, action, destIP, containerName string,
nextHopMap map[string]string) (string, error) {
buffer, err := frrPod.ExecCommand(
[]string{"ip", "route", action, destIP, "via", nextHopMap[frrPod.Definition.Spec.NodeName]}, containerName)
if err != nil {
if strings.Contains(buffer.String(), "File exists") {
glog.V(90).Infof("Warning: Route to %s already exist", destIP)

return buffer.String(), nil
}

if strings.Contains(buffer.String(), "No such process") {
glog.V(90).Infof("Warning: Route to %s already absent", destIP)

return buffer.String(), nil
}

return buffer.String(), err
}

return buffer.String(), nil
}

// BuildRoutesMapWithSpecificRoutes creates a route map with specific routes.
func BuildRoutesMapWithSpecificRoutes(podList []*pod.Builder, workerNodeList []*nodes.Builder,
nextHopList []string) (map[string]string, error) {
if len(podList) == 0 {
glog.Error("Pod list is empty")

return nil, fmt.Errorf("pod list is empty")
}

if len(nextHopList) == 0 {
glog.Error("Nexthop IP addresses list is empty")

return nil, fmt.Errorf("nexthop IP addresses list is empty")
}

if len(nextHopList) < len(podList) {
glog.Errorf("Number of speaker IP addresses[%d] is less than the number of pods[%d]", len(nextHopList), len(podList))

return nil, fmt.Errorf("insufficient speaker IP addresses: got %d, need at least %d", len(nextHopList), len(podList))
}

routesMap := make(map[string]string)

for _, frrPod := range podList {
if frrPod.Definition.Spec.NodeName == workerNodeList[0].Definition.Name {
routesMap[frrPod.Definition.Spec.NodeName] = nextHopList[1]
} else {
routesMap[frrPod.Definition.Spec.NodeName] = nextHopList[0]
}
}

return routesMap, nil
}

// DefineBaseConfig creates a map of strings for the frr configuration.
func DefineBaseConfig(daemonsConfig, frrConfig, vtyShConfig string) map[string]string {
configMapData := make(map[string]string)
configMapData["daemons"] = daemonsConfig
configMapData["frr.conf"] = frrConfig
configMapData["vtysh.conf"] = vtyShConfig

return configMapData
}

// RemovePrefixFromIPList removes the prefix from an IP address.
func RemovePrefixFromIPList(ipAddressList []string) []string {
var ipAddressListWithoutPrefix []string
for _, ipaddress := range ipAddressList {
ipAddressListWithoutPrefix = append(ipAddressListWithoutPrefix, ipaddr.RemovePrefix(ipaddress))
}

return ipAddressListWithoutPrefix
}
33 changes: 0 additions & 33 deletions tests/cnf/core/network/metallb/internal/frr/frr.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,6 @@ type (
BGPNeighborGRStatus map[string]GRStatus
)

// DefineBaseConfig defines minimal required FRR configuration.
func DefineBaseConfig(daemonsConfig, frrConfig, vtyShConfig string) map[string]string {
configMapData := make(map[string]string)
configMapData["daemons"] = daemonsConfig
configMapData["frr.conf"] = frrConfig
configMapData["vtysh.conf"] = vtyShConfig

return configMapData
}

// DefineBGPConfig returns string which represents BGP config file peering to all given IP addresses.
func DefineBGPConfig(localBGPASN, remoteBGPASN int, neighborsIPAddresses []string, multiHop, bfd bool) string {
bgpConfig := tsparams.FRRBaseConfig +
Expand Down Expand Up @@ -272,29 +262,6 @@ func GetMetricsByPrefix(frrPod *pod.Builder, metricPrefix string) ([]string, err
return collectedMetrics, nil
}

// SetStaticRoute could set or delete static route on all Speaker pods.
func SetStaticRoute(frrPod *pod.Builder, action, destIP string, nextHopMap map[string]string) (string, error) {
buffer, err := frrPod.ExecCommand(
[]string{"ip", "route", action, destIP, "via", nextHopMap[frrPod.Definition.Spec.NodeName]}, "frr")
if err != nil {
if strings.Contains(buffer.String(), "File exists") {
glog.V(90).Infof("Warning: Route to %s already exist", destIP)

return buffer.String(), nil
}

if strings.Contains(buffer.String(), "No such process") {
glog.V(90).Infof("Warning: Route to %s already absent", destIP)

return buffer.String(), nil
}

return buffer.String(), err
}

return buffer.String(), nil
}

// GetBGPStatus returns bgp status output from frr pod.
func GetBGPStatus(frrPod *pod.Builder, protocolVersion string) (*bgpStatus, error) {
glog.V(90).Infof("Getting bgp status from pod: %s", frrPod.Definition.Name)
Expand Down
Loading

0 comments on commit 5ffcef2

Please sign in to comment.