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 }