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 Feb 4, 2025
1 parent 6ae6ebb commit 5830966
Show file tree
Hide file tree
Showing 20 changed files with 881 additions and 277 deletions.
30 changes: 30 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,23 @@ 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) {
glog.V(90).Infof("Validate tcp traffic to %d to destination server IP %s", portNum, destIPAddr)

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 +178,15 @@ func getNumberOfPackets(line, firstFieldSubstr string) int {

return numberOfPackets
}

// RemovePrefixFromIPList removes the prefix from a list of IP addresses with prefixes.
func RemovePrefixFromIPList(ipAddressList []string) []string {
var ipAddressListWithoutPrefix []string

for _, ipaddress := range ipAddressList {
glog.V(90).Infof("Remove the network prefix from IP address %s", ipaddress)
ipAddressListWithoutPrefix = append(ipAddressListWithoutPrefix, ipaddr.RemovePrefix(ipaddress))
}

return ipAddressListWithoutPrefix
}
35 changes: 31 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,7 @@ 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-gotests/tests/cnf/core/internal/coreparams"
)

// MasterNadPlugin sets NetworkAttachmentDefinition master plugin based on given input.
Expand Down Expand Up @@ -54,7 +55,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 +68,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 +79,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 +92,28 @@ func createNadWithMasterPlugin(

return createdNad, nil
}

// CreateExternalNad creats an external network-attchment-definition using the br-ex interface.
func CreateExternalNad(apiClient *clients.Settings, name, testNameSpace string) error {
glog.V(90).Info("Creating external BR-EX NetworkAttachmentDefinition")

// Define the master NAD plugin
macVlanPlugin, err := MasterNadPlugin(coreparams.OvnExternalBridge, "bridge", nad.IPAMStatic())
if err != nil {
glog.V(90).Infof("Failed to define master NAD plugin: %v", err)

return err
}

// Create the NetworkAttachmentDefinition
_, err = CreateNadWithMasterPlugin(apiClient, name, testNameSpace, macVlanPlugin)
if err != nil {
glog.V(90).Infof("Failed to create external NetworkAttachmentDefinition: %v", err)

return err
}

glog.V(90).Infof("Successfully created external NetworkAttachmentDefinition: %s", name)

return nil
}
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.
`
)
26 changes: 26 additions & 0 deletions tests/cnf/core/network/internal/frrconfig/frrconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package frrconfig

import (
"github.com/openshift-kni/eco-goinfra/pkg/pod"
"gopkg.in/k8snetworkplumbingwg/multus-cni.v4/pkg/types"
)

// 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
}

// 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
}
82 changes: 82 additions & 0 deletions tests/cnf/core/network/internal/netenv/netenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package netenv
import (
"encoding/json"
"fmt"
"strings"
"time"

"github.com/golang/glog"
Expand Down Expand Up @@ -234,3 +235,84 @@ func RemoveAllPoliciesAndWaitForSriovAndMCPStable() error {
netinittools.APIClient, netparam.MCOWaitTimeout, time.Minute,
netinittools.NetConfig.CnfMcpLabel, netinittools.NetConfig.SriovOperatorNamespace)
}

// 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.V(90).Infof("Pod list is empty")

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

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

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

if len(nextHopList) < len(podList) {
glog.V(90).Infof("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
}

// 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
}

// WaitForMcpStable waits for the stability of the MCP with the given name.
func WaitForMcpStable(apiClient *clients.Settings, waitingTime, stableDuration time.Duration, mcpName string) error {
mcp, err := mco.Pull(apiClient, mcpName)

glog.V(90).Info("Waiting for mcp to be stable")

if err != nil {
return fmt.Errorf("fail to pull mcp %s from cluster due to: %s", mcpName, err.Error())
}

err = mcp.WaitToBeStableFor(stableDuration, waitingTime)

if err != nil {
glog.V(90).Infof("Failed to wait for mcp to become stable %v", err)

return err
}

return nil
}
18 changes: 0 additions & 18 deletions tests/cnf/core/network/internal/netenv/sriov.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/golang/glog"
"github.com/openshift-kni/eco-goinfra/pkg/clients"
"github.com/openshift-kni/eco-goinfra/pkg/mco"
"github.com/openshift-kni/eco-goinfra/pkg/sriov"
)

Expand Down Expand Up @@ -50,20 +49,3 @@ func WaitForSriovStable(apiClient *clients.Settings, waitingTime time.Duration,

return nil
}

// WaitForMcpStable waits for the stability of the MCP with the given name.
func WaitForMcpStable(apiClient *clients.Settings, waitingTime, stableDuration time.Duration, mcpName string) error {
mcp, err := mco.Pull(apiClient, mcpName)

if err != nil {
return fmt.Errorf("fail to pull mcp %s from cluster due to: %s", mcpName, err.Error())
}

err = mcp.WaitToBeStableFor(stableDuration, waitingTime)

if err != nil {
return fmt.Errorf("cluster is not stable: %s", err.Error())
}

return nil
}
Loading

0 comments on commit 5830966

Please sign in to comment.