k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/proxy/conntrack/conntrack.go (about) 1 //go:build linux 2 // +build linux 3 4 /* 5 Copyright 2016 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 conntrack 21 22 import ( 23 "fmt" 24 "strconv" 25 "strings" 26 27 v1 "k8s.io/api/core/v1" 28 "k8s.io/klog/v2" 29 "k8s.io/utils/exec" 30 utilnet "k8s.io/utils/net" 31 ) 32 33 // Interface for dealing with conntrack 34 type Interface interface { 35 // ClearEntriesForIP deletes conntrack entries for connections of the given 36 // protocol, to the given IP. 37 ClearEntriesForIP(ip string, protocol v1.Protocol) error 38 39 // ClearEntriesForPort deletes conntrack entries for connections of the given 40 // protocol and IP family, to the given port. 41 ClearEntriesForPort(port int, isIPv6 bool, protocol v1.Protocol) error 42 43 // ClearEntriesForNAT deletes conntrack entries for connections of the given 44 // protocol, which had been DNATted from origin to dest. 45 ClearEntriesForNAT(origin, dest string, protocol v1.Protocol) error 46 47 // ClearEntriesForPortNAT deletes conntrack entries for connections of the given 48 // protocol, which had been DNATted from the given port (on any IP) to dest. 49 ClearEntriesForPortNAT(dest string, port int, protocol v1.Protocol) error 50 } 51 52 // execCT implements Interface by execing the conntrack tool 53 type execCT struct { 54 execer exec.Interface 55 } 56 57 var _ Interface = &execCT{} 58 59 func NewExec(execer exec.Interface) Interface { 60 return &execCT{execer: execer} 61 } 62 63 // noConnectionToDelete is the error string returned by conntrack when no matching connections are found 64 const noConnectionToDelete = "0 flow entries have been deleted" 65 66 func protoStr(proto v1.Protocol) string { 67 return strings.ToLower(string(proto)) 68 } 69 70 func parametersWithFamily(isIPv6 bool, parameters ...string) []string { 71 if isIPv6 { 72 parameters = append(parameters, "-f", "ipv6") 73 } 74 return parameters 75 } 76 77 // exec executes the conntrack tool using the given parameters 78 func (ct *execCT) exec(parameters ...string) error { 79 conntrackPath, err := ct.execer.LookPath("conntrack") 80 if err != nil { 81 return fmt.Errorf("error looking for path of conntrack: %v", err) 82 } 83 klog.V(4).InfoS("Clearing conntrack entries", "parameters", parameters) 84 output, err := ct.execer.Command(conntrackPath, parameters...).CombinedOutput() 85 if err != nil { 86 return fmt.Errorf("conntrack command returned: %q, error message: %s", string(output), err) 87 } 88 klog.V(4).InfoS("Conntrack entries deleted", "output", string(output)) 89 return nil 90 } 91 92 // ClearEntriesForIP is part of Interface 93 func (ct *execCT) ClearEntriesForIP(ip string, protocol v1.Protocol) error { 94 parameters := parametersWithFamily(utilnet.IsIPv6String(ip), "-D", "--orig-dst", ip, "-p", protoStr(protocol)) 95 err := ct.exec(parameters...) 96 if err != nil && !strings.Contains(err.Error(), noConnectionToDelete) { 97 // TODO: Better handling for deletion failure. When failure occur, stale udp connection may not get flushed. 98 // These stale udp connection will keep black hole traffic. Making this a best effort operation for now, since it 99 // is expensive to baby-sit all udp connections to kubernetes services. 100 return fmt.Errorf("error deleting connection tracking state for UDP service IP: %s, error: %v", ip, err) 101 } 102 return nil 103 } 104 105 // ClearEntriesForPort is part of Interface 106 func (ct *execCT) ClearEntriesForPort(port int, isIPv6 bool, protocol v1.Protocol) error { 107 if port <= 0 { 108 return fmt.Errorf("wrong port number. The port number must be greater than zero") 109 } 110 parameters := parametersWithFamily(isIPv6, "-D", "-p", protoStr(protocol), "--dport", strconv.Itoa(port)) 111 err := ct.exec(parameters...) 112 if err != nil && !strings.Contains(err.Error(), noConnectionToDelete) { 113 return fmt.Errorf("error deleting conntrack entries for UDP port: %d, error: %v", port, err) 114 } 115 return nil 116 } 117 118 // ClearEntriesForNAT is part of Interface 119 func (ct *execCT) ClearEntriesForNAT(origin, dest string, protocol v1.Protocol) error { 120 parameters := parametersWithFamily(utilnet.IsIPv6String(origin), "-D", "--orig-dst", origin, "--dst-nat", dest, 121 "-p", protoStr(protocol)) 122 err := ct.exec(parameters...) 123 if err != nil && !strings.Contains(err.Error(), noConnectionToDelete) { 124 // TODO: Better handling for deletion failure. When failure occur, stale udp connection may not get flushed. 125 // These stale udp connection will keep black hole traffic. Making this a best effort operation for now, since it 126 // is expensive to baby sit all udp connections to kubernetes services. 127 return fmt.Errorf("error deleting conntrack entries for UDP peer {%s, %s}, error: %v", origin, dest, err) 128 } 129 return nil 130 } 131 132 // ClearEntriesForPortNAT is part of Interface 133 func (ct *execCT) ClearEntriesForPortNAT(dest string, port int, protocol v1.Protocol) error { 134 if port <= 0 { 135 return fmt.Errorf("wrong port number. The port number must be greater than zero") 136 } 137 parameters := parametersWithFamily(utilnet.IsIPv6String(dest), "-D", "-p", protoStr(protocol), "--dport", strconv.Itoa(port), "--dst-nat", dest) 138 err := ct.exec(parameters...) 139 if err != nil && !strings.Contains(err.Error(), noConnectionToDelete) { 140 return fmt.Errorf("error deleting conntrack entries for UDP port: %d, error: %v", port, err) 141 } 142 return nil 143 }