github.com/k8snetworkplumbingwg/sriov-network-operator@v1.2.1-0.20240408194816-2d2e5a45d453/test/util/network/network.go (about)

     1  package network
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strings"
     8  
     9  	netattdefv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
    10  	k8sv1 "k8s.io/api/core/v1"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  
    13  	sriovv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
    14  	testclient "github.com/k8snetworkplumbingwg/sriov-network-operator/test/util/client"
    15  	"github.com/k8snetworkplumbingwg/sriov-network-operator/test/util/cluster"
    16  )
    17  
    18  // Needed for parsing of podinfo
    19  type Network struct {
    20  	Interface string
    21  	Ips       []string
    22  }
    23  
    24  type SriovNetworkOptions func(*sriovv1.SriovNetwork)
    25  
    26  func CreateSriovNetwork(clientSet *testclient.ClientSet, intf *sriovv1.InterfaceExt, name string, namespace string, operatorNamespace string, resourceName string, ipam string, options ...SriovNetworkOptions) error {
    27  	sriovNetwork := &sriovv1.SriovNetwork{
    28  		ObjectMeta: metav1.ObjectMeta{
    29  			Name:      name,
    30  			Namespace: operatorNamespace,
    31  		},
    32  		Spec: sriovv1.SriovNetworkSpec{
    33  			ResourceName:     resourceName,
    34  			IPAM:             ipam,
    35  			NetworkNamespace: namespace,
    36  			// Enable the linkState instead of auto so even if the PF is down we can still use the VF
    37  			// for pod to pod connectivity tests in the same host
    38  			LinkState: "enable",
    39  		}}
    40  
    41  	// https://bugzilla.redhat.com/show_bug.cgi?id=2214976
    42  	if cluster.VirtualCluster() {
    43  		sriovNetwork.Spec.LinkState = ""
    44  	}
    45  
    46  	for _, o := range options {
    47  		o(sriovNetwork)
    48  	}
    49  
    50  	// We need this to be able to run the connectivity checks on Mellanox cards
    51  	if intf.DeviceID == "1015" {
    52  		sriovNetwork.Spec.SpoofChk = "off"
    53  	}
    54  
    55  	err := clientSet.Create(context.Background(), sriovNetwork)
    56  	return err
    57  }
    58  
    59  func defineSriovPolicy(generatedName string, operatorNamespace string, sriovDevice string, testNode string, numVfs int, resourceName string, deviceType string, options ...func(*sriovv1.SriovNetworkNodePolicy)) *sriovv1.SriovNetworkNodePolicy {
    60  	nodePolicy := &sriovv1.SriovNetworkNodePolicy{
    61  		ObjectMeta: metav1.ObjectMeta{
    62  			GenerateName: generatedName,
    63  			Namespace:    operatorNamespace,
    64  		},
    65  		Spec: sriovv1.SriovNetworkNodePolicySpec{
    66  			NodeSelector: map[string]string{
    67  				"kubernetes.io/hostname": testNode,
    68  			},
    69  			NumVfs:       numVfs,
    70  			ResourceName: resourceName,
    71  			Priority:     99,
    72  			NicSelector: sriovv1.SriovNetworkNicSelector{
    73  				PfNames: []string{sriovDevice},
    74  			},
    75  			DeviceType: deviceType,
    76  		},
    77  	}
    78  	for _, o := range options {
    79  		o(nodePolicy)
    80  	}
    81  	return nodePolicy
    82  }
    83  
    84  // CreateSriovPolicy creates a SriovNetworkNodePolicy and returns it
    85  func CreateSriovPolicy(clientSet *testclient.ClientSet, generatedName string, operatorNamespace string, sriovDevice string, testNode string, numVfs int, resourceName string, deviceType string, options ...func(*sriovv1.SriovNetworkNodePolicy)) (*sriovv1.SriovNetworkNodePolicy, error) {
    86  	nodePolicy := defineSriovPolicy(generatedName, operatorNamespace, sriovDevice, testNode, numVfs, resourceName, deviceType, options...)
    87  	err := clientSet.Create(context.Background(), nodePolicy)
    88  	return nodePolicy, err
    89  }
    90  
    91  // GetNicsByPrefix returns a list of pod nic names, filtered by the given
    92  // nic name prefix ifcPrefix
    93  func GetNicsByPrefix(pod *k8sv1.Pod, ifcPrefix string) ([]string, error) {
    94  	var nets []Network
    95  	nics := []string{}
    96  	err := json.Unmarshal([]byte(pod.ObjectMeta.Annotations[netattdefv1.NetworkStatusAnnot]), &nets)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	for _, net := range nets {
   101  		if strings.Index(net.Interface, ifcPrefix) == 0 {
   102  			nics = append(nics, net.Interface)
   103  		}
   104  	}
   105  	return nics, nil
   106  }
   107  
   108  // GetSriovNicIPs returns the list of ip addresses related to the given
   109  // interface name for the given pod.
   110  func GetSriovNicIPs(pod *k8sv1.Pod, ifcName string) ([]string, error) {
   111  	networksStatus, ok := pod.ObjectMeta.Annotations[netattdefv1.NetworkStatusAnnot]
   112  	if !ok {
   113  		return nil, fmt.Errorf("pod [%s] has no annotation `%s`", netattdefv1.NetworkStatusAnnot, pod.Name)
   114  	}
   115  
   116  	var nets []Network
   117  	err := json.Unmarshal([]byte(networksStatus), &nets)
   118  	if err != nil {
   119  		return nil, fmt.Errorf("can't unmarshal annotation `%s`: %w", netattdefv1.NetworkStatusAnnot, err)
   120  	}
   121  	for _, net := range nets {
   122  		if net.Interface != ifcName {
   123  			continue
   124  		}
   125  		return net.Ips, nil
   126  	}
   127  
   128  	return nil, fmt.Errorf("interface [%s] not found in pod annotation", ifcName)
   129  }
   130  
   131  // Return a definition of a macvlan NetworkAttachmentDefinition
   132  // name name
   133  // namespace namespace
   134  func CreateMacvlanNetworkAttachmentDefinition(name string, namespace string) netattdefv1.NetworkAttachmentDefinition {
   135  	return netattdefv1.NetworkAttachmentDefinition{
   136  		ObjectMeta: metav1.ObjectMeta{
   137  			Name:      name,
   138  			Namespace: namespace,
   139  		},
   140  		Spec: netattdefv1.NetworkAttachmentDefinitionSpec{
   141  			Config: `{
   142  				"cniVersion": "0.3.0",
   143  				"type": "macvlan",
   144  				"mode": "bridge",
   145  				"ipam": {
   146  				  "type": "host-local",
   147  				  "subnet": "10.1.1.0/24",
   148  				  "rangeStart": "10.1.1.100",
   149  				  "rangeEnd": "10.1.1.200",
   150  				  "routes": [
   151  					{ "dst": "0.0.0.0/0" }
   152  				  ],
   153  				  "gateway": "10.1.1.1"
   154  				}
   155  			  }`,
   156  		},
   157  	}
   158  }