Skip to content

Commit

Permalink
Introduce link watcher for ARP/NDP responders
Browse files Browse the repository at this point in the history
For secondary-network scenarios, the transport interface can be
changed after the agent is started. The ARP/NDP responders should
be started after the initialization of secondary-network to bind
to the transport interface of the new index.

Besides, this change also addresses the following issues:
- NDP responder may fail to bind to the new interface due to the
Duplicate Address Detection process.
- Golang caches the zone index for the interface, which may result
in NDP responder binding on the stale interface

Fixes: antrea-io#6623

Signed-off-by: Xu Liu <[email protected]>
  • Loading branch information
xliuxu committed Oct 23, 2024
1 parent 90b1cb9 commit 1945b5b
Show file tree
Hide file tree
Showing 21 changed files with 958 additions and 251 deletions.
9 changes: 9 additions & 0 deletions cmd/antrea-agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import (
"antrea.io/antrea/pkg/agent/flowexporter"
"antrea.io/antrea/pkg/agent/flowexporter/exporter"
"antrea.io/antrea/pkg/agent/interfacestore"
"antrea.io/antrea/pkg/agent/ipassigner/linkdetector"
"antrea.io/antrea/pkg/agent/memberlist"
"antrea.io/antrea/pkg/agent/metrics"
"antrea.io/antrea/pkg/agent/monitortool"
Expand Down Expand Up @@ -546,6 +547,7 @@ func run(o *Options) error {
var externalIPPoolController *externalippool.ExternalIPPoolController
var externalIPController *serviceexternalip.ServiceExternalIPController
var memberlistCluster *memberlist.Cluster
var linkDetector linkdetector.Interface

if o.enableEgress || features.DefaultFeatureGate.Enabled(features.ServiceExternalIP) {
externalIPPoolController = externalippool.NewExternalIPPoolController(
Expand All @@ -565,13 +567,15 @@ func run(o *Options) error {
if err != nil {
return fmt.Errorf("error creating new memberlist cluster: %v", err)
}
linkDetector = linkdetector.NewLinkDetector()
}
if o.enableEgress {
egressController, err = egress.NewEgressController(
ofClient, k8sClient, antreaClientProvider, crdClient, ifaceStore, routeClient, nodeConfig.Name, nodeConfig.NodeTransportInterfaceName,
memberlistCluster, egressInformer, externalIPPoolInformer, nodeInformer, podUpdateChannel, serviceCIDRProvider, o.config.Egress.MaxEgressIPsPerNode,
features.DefaultFeatureGate.Enabled(features.EgressTrafficShaping),
features.DefaultFeatureGate.Enabled(features.EgressSeparateSubnet),
linkDetector,
)
if err != nil {
return fmt.Errorf("error creating new Egress controller: %v", err)
Expand All @@ -584,6 +588,7 @@ func run(o *Options) error {
memberlistCluster,
serviceInformer,
endpointsInformer,
linkDetector,
)
if err != nil {
return fmt.Errorf("error creating new ServiceExternalIP controller: %v", err)
Expand Down Expand Up @@ -999,6 +1004,10 @@ func run(o *Options) error {
go nodeLatencyMonitor.Run(stopCh)
}

if linkDetector != nil {
go linkDetector.Run(stopCh)
}

<-stopCh
klog.InfoS("Stopping Antrea Agent")
return nil
Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ require (
github.com/lithammer/dedent v1.1.0
github.com/mdlayher/arp v0.0.0-20220221190821-c37aaafac7f9
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
github.com/mdlayher/ndp v0.8.0
github.com/mdlayher/ndp v1.1.0
github.com/mdlayher/packet v1.1.2
github.com/miekg/dns v1.1.62
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
Expand Down Expand Up @@ -214,7 +214,6 @@ require (
github.com/vishvananda/netns v0.0.4 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f // indirect
go.etcd.io/etcd/api/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/v3 v3.5.14 // indirect
Expand Down Expand Up @@ -251,3 +250,6 @@ require (
sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)

// remove this when https://github.com/mdlayher/ndp/pull/32 gets merged
replace github.com/mdlayher/ndp => github.com/xliuxu/ndp v0.0.0-20240926134643-8cf547505092
10 changes: 2 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
Expand Down Expand Up @@ -529,8 +528,6 @@ github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHI
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
github.com/mdlayher/ndp v0.8.0 h1:oVCl5JZSzT/YJE6cJd7EnNDWmX1fl4hJV0S/UCBNoHE=
github.com/mdlayher/ndp v0.8.0/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
Expand Down Expand Up @@ -768,12 +765,12 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/xliuxu/ndp v0.0.0-20240926134643-8cf547505092 h1:1sBcuJrdQq9bawMA4Jm58h+cwefaV5ZIx5r50T/ZgTk=
github.com/xliuxu/ndp v0.0.0-20240926134643-8cf547505092/go.mod h1:FmgESgemgjl38vuOIyAHWUUL6vQKA/pQNkvXdWsdQFM=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI=
gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
Expand Down Expand Up @@ -888,7 +885,6 @@ golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
Expand Down Expand Up @@ -916,7 +912,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -953,7 +948,6 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
9 changes: 7 additions & 2 deletions pkg/agent/controller/egress/egress_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"antrea.io/antrea/pkg/agent/client"
"antrea.io/antrea/pkg/agent/interfacestore"
"antrea.io/antrea/pkg/agent/ipassigner"
"antrea.io/antrea/pkg/agent/ipassigner/linkdetector"
"antrea.io/antrea/pkg/agent/memberlist"
"antrea.io/antrea/pkg/agent/openflow"
"antrea.io/antrea/pkg/agent/route"
Expand Down Expand Up @@ -205,6 +206,8 @@ type EgressController struct {
tableAllocator *idAllocator
// Each subnet has its own route table.
egressRouteTables map[crdv1b1.SubnetInfo]*egressRouteTable

linkDetector linkdetector.Interface
}

func NewEgressController(
Expand All @@ -225,6 +228,7 @@ func NewEgressController(
maxEgressIPsPerNode int,
trafficShapingEnabled bool,
supportSeparateSubnet bool,
linkDetector linkdetector.Interface,
) (*EgressController, error) {
if trafficShapingEnabled && !openflow.OVSMetersAreSupported() {
klog.Info("EgressTrafficShaping feature gate is enabled, but it is ignored because OVS meters are not supported.")
Expand Down Expand Up @@ -273,6 +277,7 @@ func NewEgressController(
externalIPPoolLister: externalIPPoolInformer.Lister(),
externalIPPoolListerSynced: externalIPPoolInformer.Informer().HasSynced,
supportSeparateSubnet: supportSeparateSubnet,
linkDetector: linkDetector,
}
if supportSeparateSubnet {
c.egressRouteTables = map[crdv1b1.SubnetInfo]*egressRouteTable{}
Expand All @@ -285,7 +290,7 @@ func NewEgressController(
resyncPeriod,
)
}
ipAssigner, err := newIPAssigner(nodeTransportInterface, egressDummyDevice)
ipAssigner, err := newIPAssigner(nodeTransportInterface, egressDummyDevice, linkDetector)
if err != nil {
return nil, fmt.Errorf("initializing egressIP assigner failed: %v", err)
}
Expand Down Expand Up @@ -505,7 +510,7 @@ func (c *EgressController) Run(stopCh <-chan struct{}) {
go c.localIPDetector.Run(stopCh)
go c.egressIPScheduler.Run(stopCh)
go c.ipAssigner.Run(stopCh)
if !cache.WaitForNamedCacheSync(controllerName, stopCh, c.egressListerSynced, c.externalIPPoolListerSynced, c.localIPDetector.HasSynced, c.egressIPScheduler.HasScheduled) {
if !cache.WaitForNamedCacheSync(controllerName, stopCh, c.egressListerSynced, c.externalIPPoolListerSynced, c.localIPDetector.HasSynced, c.egressIPScheduler.HasScheduled, c.linkDetector.HasSynced) {
return
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/agent/controller/egress/egress_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (

"antrea.io/antrea/pkg/agent/interfacestore"
"antrea.io/antrea/pkg/agent/ipassigner"
"antrea.io/antrea/pkg/agent/ipassigner/linkdetector"
ipassignertest "antrea.io/antrea/pkg/agent/ipassigner/testing"
"antrea.io/antrea/pkg/agent/memberlist"
openflowtest "antrea.io/antrea/pkg/agent/openflow/testing"
Expand Down Expand Up @@ -137,7 +138,7 @@ func (c *fakeSingleNodeCluster) AddClusterEventHandler(handler memberlist.Cluste

func mockNewIPAssigner(ipAssigner ipassigner.IPAssigner) func() {
originalNewIPAssigner := newIPAssigner
newIPAssigner = func(_, _ string) (ipassigner.IPAssigner, error) {
newIPAssigner = func(_, _ string, _ linkdetector.Interface) (ipassigner.IPAssigner, error) {
return ipAssigner, nil
}
return func() {
Expand Down Expand Up @@ -203,6 +204,7 @@ func newFakeController(t *testing.T, initObjects []runtime.Object) *fakeControll
255,
true,
true,
nil,
)
egressController.localIPDetector = localIPDetector
return &fakeController{
Expand Down
9 changes: 7 additions & 2 deletions pkg/agent/controller/serviceexternalip/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (

"antrea.io/antrea/pkg/agent/apis"
"antrea.io/antrea/pkg/agent/ipassigner"
"antrea.io/antrea/pkg/agent/ipassigner/linkdetector"
"antrea.io/antrea/pkg/agent/memberlist"
"antrea.io/antrea/pkg/agent/types"
"antrea.io/antrea/pkg/querier"
Expand Down Expand Up @@ -77,6 +78,8 @@ type ServiceExternalIPController struct {

assignedIPs map[string]sets.Set[string]
assignedIPsMutex sync.Mutex

linkDetector linkdetector.Interface
}

var _ querier.ServiceExternalIPStatusQuerier = (*ServiceExternalIPController)(nil)
Expand All @@ -87,6 +90,7 @@ func NewServiceExternalIPController(
cluster memberlist.Interface,
serviceInformer coreinformers.ServiceInformer,
endpointsInformer coreinformers.EndpointsInformer,
linkDetector linkdetector.Interface,
) (*ServiceExternalIPController, error) {
c := &ServiceExternalIPController{
nodeName: nodeName,
Expand All @@ -105,8 +109,9 @@ func NewServiceExternalIPController(
endpointsListerSynced: endpointsInformer.Informer().HasSynced,
externalIPStates: make(map[apimachinerytypes.NamespacedName]externalIPState),
assignedIPs: make(map[string]sets.Set[string]),
linkDetector: linkDetector,
}
ipAssigner, err := ipassigner.NewIPAssigner(nodeTransportInterface, "")
ipAssigner, err := ipassigner.NewIPAssigner(nodeTransportInterface, "", linkDetector)
if err != nil {
return nil, fmt.Errorf("initializing service external IP assigner failed: %v", err)
}
Expand Down Expand Up @@ -240,7 +245,7 @@ func (c *ServiceExternalIPController) Run(stopCh <-chan struct{}) {
klog.Infof("Starting %s", controllerName)
defer klog.Infof("Shutting down %s", controllerName)

if !cache.WaitForNamedCacheSync(controllerName, stopCh, c.serviceListerSynced, c.endpointsListerSynced) {
if !cache.WaitForNamedCacheSync(controllerName, stopCh, c.serviceListerSynced, c.endpointsListerSynced, c.linkDetector.HasSynced) {
return
}

Expand Down
13 changes: 4 additions & 9 deletions pkg/agent/ipassigner/ip_assigner_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/klog/v2"
utilnet "k8s.io/utils/net"

"antrea.io/antrea/pkg/agent/ipassigner/linkdetector"
"antrea.io/antrea/pkg/agent/ipassigner/responder"
"antrea.io/antrea/pkg/agent/util"
"antrea.io/antrea/pkg/agent/util/arping"
Expand Down Expand Up @@ -217,7 +218,7 @@ type ipAssigner struct {
}

// NewIPAssigner returns an *ipAssigner.
func NewIPAssigner(nodeTransportInterface string, dummyDeviceName string) (IPAssigner, error) {
func NewIPAssigner(nodeTransportInterface string, dummyDeviceName string, linkDetector linkdetector.Interface) (IPAssigner, error) {
ipv4, ipv6, externalInterface, err := util.GetIPNetDeviceByName(nodeTransportInterface)
if err != nil {
return nil, fmt.Errorf("get IPNetDevice from name %s error: %+v", nodeTransportInterface, err)
Expand All @@ -242,17 +243,11 @@ func NewIPAssigner(nodeTransportInterface string, dummyDeviceName string) (IPAss
return nil, err
}
if dummyDeviceName == "" || arpIgnore > 0 {
a.defaultAssignee.arpResponder, err = responder.NewARPResponder(externalInterface)
if err != nil {
return nil, fmt.Errorf("failed to create ARP responder for link %s: %v", externalInterface.Name, err)
}
a.defaultAssignee.arpResponder = responder.NewARPResponder(externalInterface.Name, linkDetector)
}
}
if ipv6 != nil {
a.defaultAssignee.ndpResponder, err = responder.NewNDPResponder(externalInterface)
if err != nil {
return nil, fmt.Errorf("failed to create NDP responder for link %s: %v", externalInterface.Name, err)
}
a.defaultAssignee.ndpResponder = responder.NewNDPResponder(externalInterface.Name, linkDetector)
}
if dummyDeviceName != "" {
a.defaultAssignee.link, err = ensureDummyDevice(dummyDeviceName)
Expand Down
31 changes: 31 additions & 0 deletions pkg/agent/ipassigner/linkdetector/link_detector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 Antrea Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package linkdetector

type LinkEventHandler func(linkName string)

type Interface interface {
LinkExists(linkName string) bool

// Run starts the detector.
Run(stopCh <-chan struct{})

// AddEventHandler registers an eventHandler of IP address update. It's not thread-safe and should be called before
// starting the detector.
AddEventHandler(handler LinkEventHandler, linkName ...string)

// HasSynced returns true if the cache has been initialized with the full lists of IP addresses.
HasSynced() bool
}
Loading

0 comments on commit 1945b5b

Please sign in to comment.