k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/proxy/ipvs/testing/fake.go (about) 1 //go:build linux 2 // +build linux 3 4 /* 5 Copyright 2017 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package testing 21 22 import ( 23 "fmt" 24 "k8s.io/utils/net" 25 26 "k8s.io/apimachinery/pkg/util/sets" 27 ) 28 29 // FakeNetlinkHandle mock implementation of proxy NetlinkHandle 30 type FakeNetlinkHandle struct { 31 // localAddresses is a network interface name to all of its IP addresses map, e.g. 32 // eth0 -> [1.2.3.4, 10.20.30.40] 33 localAddresses map[string][]string 34 35 IsIPv6 bool 36 } 37 38 // NewFakeNetlinkHandle will create a new FakeNetlinkHandle 39 func NewFakeNetlinkHandle(isIPv6 bool) *FakeNetlinkHandle { 40 fake := &FakeNetlinkHandle{ 41 localAddresses: make(map[string][]string), 42 IsIPv6: isIPv6, 43 } 44 return fake 45 } 46 47 // EnsureAddressBind is a mock implementation 48 func (h *FakeNetlinkHandle) EnsureAddressBind(address, devName string) (exist bool, err error) { 49 if len(devName) == 0 { 50 return false, fmt.Errorf("device name can't be empty") 51 } 52 if _, ok := h.localAddresses[devName]; !ok { 53 return false, fmt.Errorf("error bind address: %s to a non-exist interface: %s", address, devName) 54 } 55 for _, addr := range h.localAddresses[devName] { 56 if addr == address { 57 // return true if the address is already bound to device 58 return true, nil 59 } 60 } 61 h.localAddresses[devName] = append(h.localAddresses[devName], address) 62 return false, nil 63 } 64 65 // UnbindAddress is a mock implementation 66 func (h *FakeNetlinkHandle) UnbindAddress(address, devName string) error { 67 if len(devName) == 0 { 68 return fmt.Errorf("device name can't be empty") 69 } 70 if _, ok := h.localAddresses[devName]; !ok { 71 return fmt.Errorf("error unbind address: %s from a non-exist interface: %s", address, devName) 72 } 73 for i, addr := range h.localAddresses[devName] { 74 if addr == address { 75 // delete address from slice h.localAddresses[devName] 76 h.localAddresses[devName] = append(h.localAddresses[devName][:i], h.localAddresses[devName][i+1:]...) 77 return nil 78 } 79 } 80 // return error message if address is not found in slice h.localAddresses[devName] 81 return fmt.Errorf("address: %s is not found in interface: %s", address, devName) 82 } 83 84 // EnsureDummyDevice is a mock implementation 85 func (h *FakeNetlinkHandle) EnsureDummyDevice(devName string) (bool, error) { 86 if len(devName) == 0 { 87 return false, fmt.Errorf("device name can't be empty") 88 } 89 if _, ok := h.localAddresses[devName]; !ok { 90 // create dummy interface if devName is not found in localAddress map 91 h.localAddresses[devName] = make([]string, 0) 92 return false, nil 93 } 94 // return true if devName is already created in localAddress map 95 return true, nil 96 } 97 98 // DeleteDummyDevice is a mock implementation 99 func (h *FakeNetlinkHandle) DeleteDummyDevice(devName string) error { 100 if len(devName) == 0 { 101 return fmt.Errorf("device name can't be empty") 102 } 103 if _, ok := h.localAddresses[devName]; !ok { 104 return fmt.Errorf("error deleting a non-exist interface: %s", devName) 105 } 106 delete(h.localAddresses, devName) 107 return nil 108 } 109 110 // ListBindAddress is a mock implementation 111 func (h *FakeNetlinkHandle) ListBindAddress(devName string) ([]string, error) { 112 if len(devName) == 0 { 113 return nil, fmt.Errorf("device name can't be empty") 114 } 115 if _, ok := h.localAddresses[devName]; !ok { 116 return nil, fmt.Errorf("error list addresses from a non-exist interface: %s", devName) 117 } 118 return h.localAddresses[devName], nil 119 } 120 121 // GetLocalAddresses is a mock implementation 122 func (h *FakeNetlinkHandle) GetLocalAddresses(dev string) (sets.Set[string], error) { 123 res := sets.New[string]() 124 // list all addresses from a given network interface. 125 for _, addr := range h.localAddresses[dev] { 126 if h.isValidForSet(addr) { 127 res.Insert(addr) 128 } 129 } 130 return res, nil 131 } 132 func (h *FakeNetlinkHandle) GetAllLocalAddresses() (sets.Set[string], error) { 133 res := sets.New[string]() 134 // List all addresses from all available network interfaces. 135 for linkName := range h.localAddresses { 136 // list all addresses from a given network interface. 137 for _, addr := range h.localAddresses[linkName] { 138 if h.isValidForSet(addr) { 139 res.Insert(addr) 140 } 141 } 142 } 143 return res, nil 144 } 145 146 func (h *FakeNetlinkHandle) GetAllLocalAddressesExcept(dev string) (sets.Set[string], error) { 147 res := sets.New[string]() 148 for linkName := range h.localAddresses { 149 if linkName == dev { 150 continue 151 } 152 for _, addr := range h.localAddresses[linkName] { 153 if h.isValidForSet(addr) { 154 res.Insert(addr) 155 } 156 } 157 } 158 return res, nil 159 } 160 161 // SetLocalAddresses set IP addresses to the given interface device. It's not part of interface. 162 func (h *FakeNetlinkHandle) SetLocalAddresses(dev string, ips ...string) error { 163 if h.localAddresses == nil { 164 h.localAddresses = make(map[string][]string) 165 } 166 if len(dev) == 0 { 167 return fmt.Errorf("device name can't be empty") 168 } 169 h.localAddresses[dev] = make([]string, 0) 170 h.localAddresses[dev] = append(h.localAddresses[dev], ips...) 171 return nil 172 } 173 174 func (h *FakeNetlinkHandle) isValidForSet(ipString string) bool { 175 ip := net.ParseIPSloppy(ipString) 176 if h.IsIPv6 != (ip.To4() == nil) { 177 return false 178 } 179 if h.IsIPv6 && ip.IsLinkLocalUnicast() { 180 return false 181 } 182 if ip.IsLoopback() { 183 return false 184 } 185 return true 186 }