diff --git a/go.mod b/go.mod index c09b482c89e..62b81f3cc8b 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.1 github.com/vishvananda/netlink v1.2.1-beta.2 - golang.org/x/sys v0.2.0 + golang.org/x/sys v0.3.0 golang.org/x/time v0.2.0 google.golang.org/grpc v1.48.0 gopkg.in/k8snetworkplumbingwg/multus-cni.v3 v3.9.0 @@ -79,7 +79,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/google/gnostic v0.6.9 // indirect - github.com/google/go-cmp v0.5.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect @@ -87,7 +87,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/josharian/native v1.0.0 // indirect + github.com/josharian/native v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/juju/errors v1.0.0 // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect @@ -97,8 +97,8 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 // indirect - github.com/mdlayher/packet v1.0.0 // indirect - github.com/mdlayher/socket v0.2.3 // indirect + github.com/mdlayher/packet v1.1.1 // indirect + github.com/mdlayher/socket v0.4.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -128,11 +128,11 @@ require ( github.com/subosito/gotenv v1.4.0 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect go.opencensus.io v0.23.0 // indirect - golang.org/x/net v0.2.0 // indirect + golang.org/x/net v0.4.0 // indirect golang.org/x/oauth2 v0.2.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/term v0.2.0 // indirect - golang.org/x/text v0.4.0 // indirect + golang.org/x/term v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d // indirect @@ -162,6 +162,7 @@ replace ( github.com/alauda/felix => github.com/kubeovn/felix v0.0.0-20220325073257-c8a0f705d139 github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2 github.com/greenpau/ovsdb => github.com/kubeovn/ovsdb v0.0.0-20221213053943-9372db56919f + github.com/mdlayher/arp => github.com/kubeovn/arp v0.0.0-20230101053045-8a0772d9c34c github.com/openshift/api => github.com/openshift/api v0.0.0-20210428205234-a8389931bee7 github.com/openshift/client-go => github.com/openshift/client-go v0.0.0-20210112165513-ebc401615f47 github.com/openshift/library-go => github.com/mhenriks/library-go v0.0.0-20210511195009-51ba86622560 diff --git a/go.sum b/go.sum index efb11a9aec0..dc9f391a4dd 100644 --- a/go.sum +++ b/go.sum @@ -637,8 +637,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -776,8 +776,9 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -826,6 +827,8 @@ github.com/kr/text v0.0.0-20160504234017-7cafcd837844/go.mod h1:sjUstKUATFIcff4q github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kubeovn/arp v0.0.0-20230101053045-8a0772d9c34c h1:AcOKlV+lInNlGO3o3+1ZIpHxiUvGiQnYsis6PfSk61Q= +github.com/kubeovn/arp v0.0.0-20230101053045-8a0772d9c34c/go.mod h1:Ce8lvkopTGXfPmeb5AY3/umEOmoFVV3HlCPGfGk0+Y0= github.com/kubeovn/felix v0.0.0-20220325073257-c8a0f705d139 h1:MaLC8/dohKHU8nkfglfE2oikefB6urJG75yZDOcKTRU= github.com/kubeovn/felix v0.0.0-20220325073257-c8a0f705d139/go.mod h1:ulxnUH9cbIOtCH+exhJPeV2mleh+bDv67WKsl/MVU/g= github.com/kubeovn/libovsdb v0.0.0-20221125061852-8b910935f8e4 h1:S/R2b2/S7L3l68Y2YwV/0zDGEVDargfRVqYu6989fIw= @@ -879,15 +882,14 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875 h1:ql8x//rJsHMjS+qqEag8n3i4azw1QneKh5PieH9UEbY= -github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875/go.mod h1:kfOoFJuHWp76v1RgZCb9/gVUc7XdY877S2uVYbNliGc= github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE= github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og= -github.com/mdlayher/packet v1.0.0 h1:InhZJbdShQYt6XV2GPj5XHxChzOfhJJOMbvnGAmOfQ8= github.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jmnjzPjOU= +github.com/mdlayher/packet v1.1.1 h1:7Fv4OEMYqPl7//uBm04VgPpnSNi8fbBZznppgh6WMr8= +github.com/mdlayher/packet v1.1.1/go.mod h1:DRvYY5mH4M4lUqAnMg04E60U4fjUKMZ/4g2cHElZkKo= github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= -github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= -github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= +github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= +github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= @@ -1494,8 +1496,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1645,12 +1647,12 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170730040918-3bd178b88a81/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1663,8 +1665,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/daemon/handler.go b/pkg/daemon/handler.go index 73373ad2d8a..0ea58474355 100644 --- a/pkg/daemon/handler.go +++ b/pkg/daemon/handler.go @@ -244,14 +244,15 @@ func (csh cniServerHandler) handleAdd(req *restful.Request, resp *restful.Respon mtu = csh.Config.MTU } + detectIPConflict := podSubnet.Spec.Vlan != "" klog.Infof("create container interface %s mac %s, ip %s, cidr %s, gw %s, custom routes %v", ifName, macAddr, ipAddr, cidr, gw, podRequest.Routes) if nicType == util.InternalType { - podNicName, err = csh.configureNicWithInternalPort(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, podRequest.Routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, priority, podRequest.DeviceID, nicType, latency, limit, loss, gatewayCheckMode) + podNicName, err = csh.configureNicWithInternalPort(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, detectIPConflict, podRequest.Routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, priority, podRequest.DeviceID, nicType, latency, limit, loss, gatewayCheckMode) } else if nicType == util.DpdkType { err = csh.configureDpdkNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, ingress, egress, priority, getShortSharedDir(pod.UID, podRequest.VhostUserSocketVolumeName), podRequest.VhostUserSocketName) } else { podNicName = ifName - err = csh.configureNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, podRequest.VfDriver, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, podRequest.Routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, priority, podRequest.DeviceID, nicType, latency, limit, loss, gatewayCheckMode) + err = csh.configureNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, podRequest.VfDriver, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, detectIPConflict, podRequest.Routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, priority, podRequest.DeviceID, nicType, latency, limit, loss, gatewayCheckMode) } if err != nil { errMsg := fmt.Errorf("configure nic failed %v", err) diff --git a/pkg/daemon/ovs_linux.go b/pkg/daemon/ovs_linux.go index 93396b91c5a..4cca91fb018 100644 --- a/pkg/daemon/ovs_linux.go +++ b/pkg/daemon/ovs_linux.go @@ -55,7 +55,7 @@ func (csh cniServerHandler) configureDpdkNic(podName, podNamespace, provider, ne return nil } -func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, containerID, vfDriver, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, priority, DeviceID, nicType, latency, limit, loss string, gwCheckMode int) error { +func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, containerID, vfDriver, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute, detectIPConflict bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, priority, DeviceID, nicType, latency, limit, loss string, gwCheckMode int) error { var err error var hostNicName, containerNicName string if DeviceID == "" { @@ -120,7 +120,7 @@ func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, if err != nil { return fmt.Errorf("failed to open netns %q: %v", netns, err) } - if err = configureContainerNic(containerNicName, ifName, ip, gateway, isDefaultRoute, routes, macAddr, podNS, mtu, nicType, gwCheckMode); err != nil { + if err = configureContainerNic(containerNicName, ifName, ip, gateway, isDefaultRoute, detectIPConflict, routes, macAddr, podNS, mtu, nicType, gwCheckMode); err != nil { return err } return nil @@ -200,7 +200,7 @@ func configureHostNic(nicName string) error { return nil } -func configureContainerNic(nicName, ifName string, ipAddr, gateway string, isDefaultRoute bool, routes []request.Route, macAddr net.HardwareAddr, netns ns.NetNS, mtu int, nicType string, gwCheckMode int) error { +func configureContainerNic(nicName, ifName string, ipAddr, gateway string, isDefaultRoute, detectIPConflict bool, routes []request.Route, macAddr net.HardwareAddr, netns ns.NetNS, mtu int, nicType string, gwCheckMode int) error { containerLink, err := netlink.LinkByName(nicName) if err != nil { return fmt.Errorf("can not find container nic %s: %v", nicName, err) @@ -246,11 +246,11 @@ func configureContainerNic(nicName, ifName string, ipAddr, gateway string, isDef if err = configureAdditionalNic(ifName, ipAddr); err != nil { return err } - if err = configureNic(nicName, ipAddr, macAddr, mtu); err != nil { + if err = configureNic(nicName, ipAddr, macAddr, mtu, detectIPConflict); err != nil { return err } } else { - if err = configureNic(ifName, ipAddr, macAddr, mtu); err != nil { + if err = configureNic(ifName, ipAddr, macAddr, mtu, detectIPConflict); err != nil { return err } } @@ -343,7 +343,7 @@ func waitNetworkReady(nic, ipAddr, gateway string, underlayGateway, verbose bool for i, gw := range strings.Split(gateway, ",") { src := strings.Split(ips[i], "/")[0] if underlayGateway && util.CheckProtocol(gw) == kubeovnv1.ProtocolIPv4 { - mac, count, err := util.Arping(nic, src, gw, time.Second, gatewayCheckMaxRetry) + mac, count, err := util.ArpResolve(nic, src, gw, time.Second, gatewayCheckMaxRetry) cniConnectivityResult.WithLabelValues(nodeName).Add(float64(count)) if err != nil { err = fmt.Errorf("network %s with gateway %s is not ready for interface %s after %d checks: %v", ips[i], gw, nic, count, err) @@ -374,7 +374,7 @@ func configureNodeNic(portName, ip, gw string, macAddr net.HardwareAddr, mtu int return fmt.Errorf(raw) } - if err = configureNic(util.NodeNic, ip, macAddr, mtu); err != nil { + if err = configureNic(util.NodeNic, ip, macAddr, mtu, false); err != nil { return err } @@ -439,12 +439,28 @@ func configureMirrorLink(portName string, mtu int) error { return nil } -func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int) error { +func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int, detectIPConflict bool) error { nodeLink, err := netlink.LinkByName(link) if err != nil { return fmt.Errorf("can not find nic %s: %v", link, err) } + if err = netlink.LinkSetHardwareAddr(nodeLink, macAddr); err != nil { + return fmt.Errorf("can not set mac address to nic %s: %v", link, err) + } + + if mtu > 0 { + if err = netlink.LinkSetMTU(nodeLink, mtu); err != nil { + return fmt.Errorf("can not set nic %s mtu: %v", link, err) + } + } + + if nodeLink.Attrs().OperState != netlink.OperUp { + if err = netlink.LinkSetUp(nodeLink); err != nil { + return fmt.Errorf("can not set node nic %s up: %v", link, err) + } + } + ipDelMap := make(map[string]netlink.Addr) ipAddMap := make(map[string]netlink.Addr) ipAddrs, err := netlink.AddrList(nodeLink, 0x0) @@ -479,26 +495,24 @@ func configureNic(link, ip string, macAddr net.HardwareAddr, mtu int) error { } } for _, addr := range ipAddMap { - if err = netlink.AddrAdd(nodeLink, &addr); err != nil { - return fmt.Errorf("can not add address %v to nic %s: %v", addr, link, err) + if detectIPConflict && addr.IP.To4() != nil { + ip := addr.IP.String() + mac, err := util.ArpDetectIPConflict(link, ip, macAddr) + if err != nil { + err = fmt.Errorf("failed to detect address conflict for %s on link %s: %v", ip, link, err) + klog.Error(err) + return err + } + if mac != nil { + return fmt.Errorf("IP address %s has already been used by host with MAC %s", ip, mac) + } } - } - if err = netlink.LinkSetHardwareAddr(nodeLink, macAddr); err != nil { - return fmt.Errorf("can not set mac address to nic %s: %v", link, err) - } - - if mtu > 0 { - if err = netlink.LinkSetMTU(nodeLink, mtu); err != nil { - return fmt.Errorf("can not set nic %s mtu: %v", link, err) + if err = netlink.AddrAdd(nodeLink, &addr); err != nil { + return fmt.Errorf("can not add address %v to nic %s: %v", addr, link, err) } } - if nodeLink.Attrs().OperState != netlink.OperUp { - if err = netlink.LinkSetUp(nodeLink); err != nil { - return fmt.Errorf("can not set node nic %s up: %v", link, err) - } - } return nil } @@ -837,7 +851,7 @@ func renameLink(curName, newName string) error { return nil } -func (csh cniServerHandler) configureNicWithInternalPort(podName, podNamespace, provider, netns, containerID, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, priority, DeviceID, nicType, latency, limit, loss string, gwCheckMode int) (string, error) { +func (csh cniServerHandler) configureNicWithInternalPort(podName, podNamespace, provider, netns, containerID, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute, detectIPConflict bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, priority, DeviceID, nicType, latency, limit, loss string, gwCheckMode int) (string, error) { _, containerNicName := generateNicName(containerID, ifName) ipStr := util.GetIpWithoutMask(ip) ifaceID := ovs.PodNameToPortName(podName, podNamespace, provider) @@ -873,7 +887,7 @@ func (csh cniServerHandler) configureNicWithInternalPort(podName, podNamespace, if err != nil { return containerNicName, fmt.Errorf("failed to open netns %q: %v", netns, err) } - if err = configureContainerNic(containerNicName, ifName, ip, gateway, isDefaultRoute, routes, macAddr, podNS, mtu, nicType, gwCheckMode); err != nil { + if err = configureContainerNic(containerNicName, ifName, ip, gateway, isDefaultRoute, detectIPConflict, routes, macAddr, podNS, mtu, nicType, gwCheckMode); err != nil { return containerNicName, err } return containerNicName, nil diff --git a/pkg/daemon/ovs_windows.go b/pkg/daemon/ovs_windows.go index 8694f042130..77fa2b3ee50 100644 --- a/pkg/daemon/ovs_windows.go +++ b/pkg/daemon/ovs_windows.go @@ -22,11 +22,11 @@ func (csh cniServerHandler) configureDpdkNic(podName, podNamespace, provider, ne return errors.New("DPDK is not supported on Windows") } -func (csh cniServerHandler) configureNicWithInternalPort(podName, podNamespace, provider, netns, containerID, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, priority, DeviceID, nicType, latency, limit, loss string, gwCheckMode int) (string, error) { - return ifName, csh.configureNic(podName, podNamespace, provider, netns, containerID, "", ifName, mac, mtu, ip, gateway, isDefaultRoute, routes, dnsServer, dnsSuffix, ingress, egress, priority, DeviceID, nicType, latency, limit, loss, gwCheckMode) +func (csh cniServerHandler) configureNicWithInternalPort(podName, podNamespace, provider, netns, containerID, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute, detectIPConflict bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, priority, DeviceID, nicType, latency, limit, loss string, gwCheckMode int) (string, error) { + return ifName, csh.configureNic(podName, podNamespace, provider, netns, containerID, "", ifName, mac, mtu, ip, gateway, isDefaultRoute, detectIPConflict, routes, dnsServer, dnsSuffix, ingress, egress, priority, DeviceID, nicType, latency, limit, loss, gwCheckMode) } -func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, containerID, vfDriver, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, priority, DeviceID, nicType, latency, limit, loss string, gwCheckMode int) error { +func (csh cniServerHandler) configureNic(podName, podNamespace, provider, netns, containerID, vfDriver, ifName, mac string, mtu int, ip, gateway string, isDefaultRoute, detectIPConflict bool, routes []request.Route, dnsServer, dnsSuffix []string, ingress, egress, priority, DeviceID, nicType, latency, limit, loss string, gwCheckMode int) error { if DeviceID != "" { return errors.New("SR-IOV is not supported on Windows") } diff --git a/pkg/util/arp.go b/pkg/util/arp.go new file mode 100644 index 00000000000..026194547ce --- /dev/null +++ b/pkg/util/arp.go @@ -0,0 +1,227 @@ +//go:build !windows +// +build !windows + +package util + +import ( + "fmt" + "math/rand" + "net" + "net/netip" + "sync" + "time" + + "github.com/mdlayher/arp" + "k8s.io/klog/v2" +) + +func init() { + rand.Seed(int64(time.Now().Nanosecond())) +} + +func ArpResolve(nic, srcIP, dstIP string, timeout time.Duration, maxRetry int) (net.HardwareAddr, int, error) { + target, err := netip.ParseAddr(dstIP) + if err != nil { + return nil, 0, fmt.Errorf("failed to parse target address %s: %v", dstIP, err) + } + + var count int + var ifi *net.Interface + for ; count < maxRetry; count++ { + if ifi, err = net.InterfaceByName(nic); err == nil { + break + } + time.Sleep(timeout) + } + if err != nil { + return nil, count, fmt.Errorf("failed to get interface %s: %v", nic, err) + } + + var client *arp.Client + for ; count < maxRetry; count++ { + if client, err = arp.Dial(ifi); err == nil { + defer client.Close() + break + } + time.Sleep(timeout) + } + if err != nil { + return nil, count, fmt.Errorf("failed to set up ARP client: %v", err) + } + + var mac net.HardwareAddr + for ; count < maxRetry; count++ { + if err = client.SetDeadline(time.Now().Add(timeout)); err != nil { + continue + } + if mac, err = client.Resolve(target); err == nil { + return mac, count + 1, nil + } + } + + return nil, count, fmt.Errorf("resolve MAC address of %s timeout: %v", dstIP, err) +} + +func macEqual(a, b net.HardwareAddr) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} + +// https://www.ietf.org/rfc/rfc5227.txt +// returns MAC of the host if the ip address is in use +func ArpDetectIPConflict(nic, ip string, mac net.HardwareAddr) (net.HardwareAddr, error) { + const ( + probeWait = 1 * time.Second // initial random delay + probeNum = 3 // number of probe packets + probeMin = 1 * time.Second // minimum delay until repeated probe + probeMax = 2 * time.Second // maximum delay until repeated probe + announceWait = 2 * time.Second // delay before announcing + announceNum = 2 // number of Announcement packets + announceInterval = 2 * time.Second // time between Announcement packets + ) + + tpa, err := netip.ParseAddr(ip) + if err != nil { + return nil, fmt.Errorf("failed to parse IP address %s: %v", ip, err) + } + ip = tpa.String() + + spa := netip.AddrFrom4([4]byte{0, 0, 0, 0}) + tha := net.HardwareAddr{0, 0, 0, 0, 0, 0} + pkt, err := arp.NewPacket(arp.OperationRequest, mac, spa, tha, tpa) + if err != nil { + return nil, err + } + + ifi, err := net.InterfaceByName(nic) + if err != nil { + return nil, err + } + + client, err := arp.Dial(ifi) + if err != nil { + return nil, err + } + defer client.Close() + + deadline := time.Now() + durations := make([]time.Duration, probeNum) + // wait for a random time interval selected uniformly in the range zero to + // PROBE_WAIT seconds + durations[0] = time.Duration(rand.Int63n(int64(probeWait))) + deadline = deadline.Add(durations[0]) + for i := 1; i < probeNum; i++ { + // send PROBE_NUM probe packets, each of these probe packets spaced + // randomly and uniformly, PROBE_MIN to PROBE_MAX seconds apart + durations[i] = probeMin + time.Duration(rand.Int63n(int64(probeMax-probeMin))) + deadline = deadline.Add(durations[i]) + } + + var readErr error + var wg sync.WaitGroup + ch := make(chan net.HardwareAddr, 1) + wg.Add(1) + go func() { + defer wg.Done() + + for { + if time.Now().After(deadline) { + break + } + + if readErr = client.SetReadDeadline(deadline); readErr != nil { + return + } + + pkt, _, err := client.Read() + if err != nil { + if opErr, ok := err.(*net.OpError); ok { + if netErr, ok := opErr.Err.(net.Error); ok && netErr.Timeout() { + // read timeout, ignore + return + } + } + readErr = err + return + } + + if pkt.SenderIP.String() == ip { + ch <- pkt.SenderHardwareAddr + return + } + + spa := pkt.SenderIP.As4() + if pkt.Operation == arp.OperationRequest && + net.IP(spa[:]).Equal(net.IPv4zero) && + macEqual(pkt.TargetHardwareAddr, tha) && + pkt.TargetIP.String() == ip && + !macEqual(pkt.SenderHardwareAddr, mac) { + // received probe from another host + // treat this as an address conflict + klog.Infof("received IPv4 address probe for %s from host %s", ip, pkt.SenderHardwareAddr.String()) + ch <- pkt.SenderHardwareAddr + return + } + } + }() + + dstMac := net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + for i := 0; i < probeNum; i++ { + time.Sleep(durations[i]) + + select { + case mac := <-ch: + // the IPv4 address is in use by another host + return mac, nil + default: + } + + if err = client.SetWriteDeadline(time.Now().Add(time.Second)); err != nil { + return nil, err + } + if err = client.WriteTo(pkt, dstMac); err != nil { + return nil, err + } + } + + wg.Wait() + + if readErr != nil { + klog.Error(readErr) + return nil, readErr + } + + // The address may be used safely. Broadcast ANNOUNCE_NUM ARP + // Announcements, spaced ANNOUNCE_INTERVAL seconds apart. An ARP + // Announcement is identical to the ARP Probe described above, + // except that now the sender and target IP addresses are both + // set to the host's newly selected IPv4 address. + if pkt, err = arp.NewPacket(arp.OperationRequest, mac, tpa, tha, tpa); err != nil { + return nil, err + } + + for i := 0; i < announceNum; i++ { + c := time.NewTimer(announceInterval) + if err = client.SetDeadline(time.Now().Add(announceInterval)); err != nil { + return nil, err + } + if err = client.WriteTo(pkt, dstMac); err != nil { + return nil, err + } + if i == announceNum-1 { + // the last one, no need to wait + c.Stop() + } else { + <-c.C + } + } + + return nil, nil +} diff --git a/pkg/util/arping.go b/pkg/util/arping.go deleted file mode 100644 index ef6c9a6c86e..00000000000 --- a/pkg/util/arping.go +++ /dev/null @@ -1,56 +0,0 @@ -//go:build !windows -// +build !windows - -package util - -import ( - "fmt" - "net" - "net/netip" - "time" - - "github.com/mdlayher/arp" -) - -func Arping(nic, srcIP, dstIP string, timeout time.Duration, maxRetry int) (net.HardwareAddr, int, error) { - target, err := netip.ParseAddr(dstIP) - if err != nil { - return nil, 0, fmt.Errorf("failed to parse target address %s: %v", dstIP, err) - } - - var count int - var ifi *net.Interface - for ; count < maxRetry; count++ { - if ifi, err = net.InterfaceByName(nic); err == nil { - break - } - time.Sleep(timeout) - } - if err != nil { - return nil, count, fmt.Errorf("failed to get interface %s: %v", nic, err) - } - - var client *arp.Client - for ; count < maxRetry; count++ { - if client, err = arp.Dial(ifi); err == nil { - defer client.Close() - break - } - time.Sleep(timeout) - } - if err != nil { - return nil, count, fmt.Errorf("failed to set up ARP client: %v", err) - } - - var mac net.HardwareAddr - for ; count < maxRetry; count++ { - if err = client.SetDeadline(time.Now().Add(timeout)); err != nil { - continue - } - if mac, err = client.Resolve(target); err == nil { - return mac, count + 1, nil - } - } - - return nil, count, fmt.Errorf("resolve MAC address of %s timeout: %v", dstIP, err) -}