diff --git a/README.md b/README.md
index 7795dad..b2187be 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
[](https://opensource.org/licenses/BSD-2)
-
+
[](https://goreportcard.com/report/github.com/cybertec-postgresql/vip-manager)
[](https://github.com/cybertec-postgresql/vip-manager/releases/latest)
[](https://github.com/cybertec-postgresql/vip-manager/releases)
@@ -9,6 +9,7 @@
Manages a virtual IP based on state kept in `etcd`, `Consul` or using `Patroni` REST API
## Table of Contents
+
- [Prerequisites](#prerequisites)
- [Building](#building)
- [Installing from package](#installing-from-package)
@@ -17,7 +18,7 @@ Manages a virtual IP based on state kept in `etcd`, `Consul` or using `Patroni`
- [PostgreSQL prerequisites](#postgresql-prerequisites)
- [Configuration](#configuration)
- [Configuration - Hetzner](#configuration---hetzner)
- - [Credential File - Hetzmer](#credential-file---hetzner)
+ - [Credential File - Hetzmer](#credential-file---hetzner)
- [Debugging](#debugging)
- [Author](#author)
@@ -28,25 +29,34 @@ Manages a virtual IP based on state kept in `etcd`, `Consul` or using `Patroni`
- `goreleaser` (optional)
## Building
+
1. clone this repo
-```
+
+```shell
git clone https://github.com/cybertec-postgresql/vip-manager.git
```
-2. Build the binary using `make` or `go build`.
-5. To build your own packages (.deb, .rpm, .zip, etc.), run
-```
+
+1. Build the binary using `make` or `go build`.
+
+1. To build your own packages (.deb, .rpm, .zip, etc.), run
+
+```shell
make package
```
-or
-```
+
+or
+
+```shell
goreleaser release --snapshot --skip-publish --rm-dist
```
## Installing from package
+
You can download .rpm or .deb packages here, on the [Releases](https://github.com/cybertec-postgresql/vip-manager/releases) page.
On Debian and Ubuntu, the universe repositories should provide you with vip-manager, though the version may be not as recent.
-> **Warning**
-> Our packages are probably not compatible with the one from those repositories, do not try to install them side-by-side.
+
+> [!IMPORTANT]
+Our packages are probably not compatible with the one from those repositories, do not try to install them side-by-side.
## Installing from source
@@ -54,15 +64,15 @@ On Debian and Ubuntu, the universe repositories should provide you with vip-mana
- Run `DESTDIR=/tmp make install` to copy the binary, service files and config file into the destination of your choice.
- Edit config to your needs, then run `systemctl daemon-reload`, then `systemctl start vip-manager`.
-> **Note**
-> systemd will only pick the service files up if you chose a `DESTDIR` so that it can find it. Usually `DESTDIR=''` should work.
+> [!NOTE]
+systemd will only pick the service files up if you chose a `DESTDIR` so that it can find it. Usually `DESTDIR=''` should work.
## Environment prerequisites
When vip-manager is in charge of registering and deregistering the VIP locally, it needs superuser privileges to do so.
This is not required when vip-manager is used to manage a VIP through some API, e.g. Hetzner Robot API or Hetzner Cloud API.
-> **Note**
+> [!NOTE]
> At some point it would be great to reduce this requirement to only the `CAP_NET_RAW` and `CAP_NET_ADMIN` capabilities, which could be added by a superuser to the vip-manager binary _once_.
> Right now, this is not possible since vip-manager launches plain shell commands to register and deregister virtual IP addresses locally (at least on linux), so the whole user would need these privileges.
> When vip-manager is eventually taught to directly use a library that directly uses the Linux kernel's API to register/deregister the VIP, the capabilities set for the binary will suffice.
@@ -74,15 +84,19 @@ to all found network interfaces. So something like `*` or `0.0.0.0` (IPv4 only)
to activate the automatic binding. This again might not be suitable for all use cases where security is paramount for example.
### nonlocal bind
+
If you can't set `listen_addresses` to a wildcard address, you can explicitly specify only those adresses that you want to listen to.
However, if you add the virtual IP to those addresses, PostgreSQL will fail to start when that address is not yet registered on one of the interfaces of the machine.
You need to configure the kernel to allow "nonlocal bind" of IP (v4) addresses:
+
- temporarily:
+
```bash
sysctl -w net.ipv4.ip_nonlocal_bind=1
```
- permanently:
+
```bash
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
sysctl -p
@@ -92,18 +106,19 @@ sysctl -p
The configuration can be passed to the executable through argument flags, environment variables or through a YAML config file. Run `vip-manager --help` to see the available flags.
-> **Note**
+> [!NOTE]
> The location of the YAML config file can be specified with the --config flag.
> An exemplary config file is installed into `/etc/default/vip-manager.yml` or is available in the vipconfig directory in the repository of the software.
Configuration is now (from release v1.0 on) handled using the [`viper`](https://github.com/spf13/viper) library.
This means that environment variables, command line flags, and config files can be used to configure vip-manager.
When using different configuration sources simultaneously, this is the precedence order:
+
- flag
- env
- config
-> **Note**
+> [!NOTE]
> So flags always overwrite env variables and entries from the config file. Env variables overwrite the config file entries.
All flags and file entries are written in lower case. To make longer multi-word flags and entries readable, they are separated by dashes, e.g. `retry-num`.
@@ -112,38 +127,42 @@ If you put a flag or file entry into uppercase and replace dashes with underscor
This is a list of all avaiable configuration items:
-| flag/yaml key | env notation | required | example | description |
-| ----------------- | --------------------- | --------- | ------------------------- | ----------- |
-`ip` | `VIP_IP` | yes | 10.10.10.123 | The virtual IP address that will be managed.
-`netmask` | `VIP_NETMASK` | yes | 24 | The netmask that is associated with the subnet that the virtual IP `vip` is part of.
-`interface` | `VIP_INTERFACE` | yes | eth0 | A local network interface on the machine that runs vip-manager. Required when using `manager-type=basic`. The vip will be added to and removed from this interface.
-`trigger-key` | `VIP_TRIGGER_KEY` | yes | /service/pgcluster/leader | The key in the DCS or the Patroni REST endpoint (e.g. `/leader`) that will be monitored by vip-manager. Must match `//leader` from Patroni config. When the value returned by the DCS equals `trigger-value`, vip-manager will make sure that the virtual IP is registered to this machine. If it does not match, vip-manager makes sure that the virtual IP is not registered to this machine.
-`trigger-value` | `VIP_TRIGGER_VALUE` | no | pgcluster_member_1 | The value that the DCS' answer for `trigger-key` will be matched to. Must match `` from Patroni config for DCS or the HTTP response for Patroni REST API. This is usually set to the name of the Patroni cluster member that this vip-manager instance is associated with. Defaults to the machine's hostname or to 200 for Patroni.
-`manager-type` | `VIP_MANAGER_TYPE` | no | basic | Either `basic` or `hetzner`. This describes the mechanism that is used to manage the virtual IP. Defaults to `basic`.
-`dcs-type` | `VIP_DCS_TYPE` | no | etcd | The type of DCS that vip-manager will use to monitor the `trigger-key`. Defaults to `etcd`.
-`dcs-endpoints` | `VIP_DCS_ENDPOINTS` | no | http://10.10.11.1:2379 | A url that defines where to reach the DCS or Patroni REST API. Multiple endpoints can be passed to the flag or env variable using a comma-separated-list. In the config file, a list can be specified, see the sample config for an example. Defaults to `http://127.0.0.1:2379` for `dcs-type=etcd`, `http://127.0.0.1:8500` for `dcs-type=consul` and `http://127.0.0.1:8008` for `dcs-type=patroni`.
-`etcd-user` | `VIP_ETCD_USER` | no | patroni | A username that is allowed to look at the `trigger-key` in an etcd DCS. Optional when using `dcs-type=etcd` .
-`etcd-password` | `VIP_ETCD_PASSWORD` | no | snakeoil | The password for `etcd-user`. Optional when using `dcs-type=etcd` . Requires that `etcd-user` is also set.
-`consul-token` | `VIP_CONSUL_TOKEN` | no | snakeoil | A token that can be used with the consul-API for authentication. Optional when using `dcs-type=consul` .
-`interval` | `VIP_INTERVAL` | no | 1000 | The time vip-manager main loop sleeps before checking for changes. Measured in ms. Defaults to `1000`. Doesn't affect etcd checker since v2.3.0.
-`retry-after` | `VIP_RETRY_AFTER` | no | 250 | The time to wait before retrying interactions with components outside of vip-manager. Measured in ms. Defaults to `250`.
-`retry-num` | `VIP_RETRY_NUM` | no | 3 | The number of times interactions with components outside of vip-manager are retried. Defaults to `3`.
-`etcd-ca-file` | `VIP_ETCD_CA_FILE` | no | /etc/etcd/ca.cert.pem | A certificate authority file that can be used to verify the certificate provided by etcd endpoints. Make sure to change `dcs-endpoints` to reflect that `https` is used.
-`etcd-cert-file` | `VIP_ETCD_CERT_FILE` | no | /etc/etcd/client.cert.pem | A client certificate that is used to authenticate against etcd endpoints. Requires `etcd-ca-file` to be set as well.
-`etcd-key-file` | `VIP_ETCD_KEY_FILE` | no | /etc/etcd/client.key.pem | A private key for the client certificate, used to decrypt messages sent by etcd endpoints. Required when `etcd-cert-file` is specified.
-`verbose` | `VIP_VERBOSE` | no | true | Enable more verbose logging. Currently only the manager-type=hetzner provides additional logs.
+| flag/yaml key | env notation | required | example | description |
+| ----------------- | --------------------- | --------- | --------------------------- | ----------- |
+| `ip` | `VIP_IP` | yes | `10.10.10.123` | The virtual IP address that will be managed. |
+| `netmask` | `VIP_NETMASK` | yes | `24` | The netmask that is associated with the subnet that the virtual IP `vip` is part of. |
+| `interface` | `VIP_INTERFACE` | yes | `eth0` | A local network interface on the machine that runs vip-manager. Required when using `manager-type=basic`. The vip will be added to and removed from this interface. |
+| `trigger-key` | `VIP_TRIGGER_KEY` | yes | `/service/pgcluster/leader` | The key in the DCS or the Patroni REST endpoint (e.g. `/leader`) that will be monitored by vip-manager. Must match `//leader` from Patroni config. When the value returned by the DCS equals `trigger-value`, vip-manager will make sure that the virtual IP is registered to this machine. If it does not match, vip-manager makes sure that the virtual IP is not registered to this machine. |
+| `trigger-value` | `VIP_TRIGGER_VALUE` | no | `pgcluster_member_1` | The value that the DCS' answer for `trigger-key` will be matched to. Must match `` from Patroni config for DCS or the HTTP response for Patroni REST API. This is usually set to the name of the Patroni cluster member that this vip-manager instance is associated with. Defaults to the machine's hostname or to 200 for Patroni. |
+| `manager-type` | `VIP_MANAGER_TYPE` | no | `basic` | Either `basic` or `hetzner`. This describes the mechanism that is used to manage the virtual IP. Defaults to `basic`. |
+| `dcs-type` | `VIP_DCS_TYPE` | no | `etcd` | The type of DCS that vip-manager will use to monitor the `trigger-key`. Defaults to `etcd`. |
+| `dcs-endpoints` | `VIP_DCS_ENDPOINTS` | no | `http://10.10.11.1:2379` | A url that defines where to reach the DCS or Patroni REST API. Multiple endpoints can be passed to the flag or env variable using a comma-separated-list. In the config file, a list can be specified, see the sample config for an example. Defaults to `http://127.0.0.1:2379` for `dcs-type=etcd`, `http://127.0.0.1:8500` for `dcs-type=consul` and `http://127.0.0.1:8008` for `dcs-type=patroni`. |
+| `etcd-user` | `VIP_ETCD_USER` | no | `patroni` | A username that is allowed to look at the `trigger-key` in an etcd DCS. Optional when using `dcs-type=etcd` . |
+| `etcd-password` | `VIP_ETCD_PASSWORD` | no | `snakeoil` | The password for `etcd-user`. Optional when using `dcs-type=etcd` . Requires that `etcd-user` is also set. |
+| `consul-token` | `VIP_CONSUL_TOKEN` | no | `snakeoil` | A token that can be used with the consul-API for authentication. Optional when using `dcs-type=consul` . |
+| `interval` | `VIP_INTERVAL` | no | `1000` | The time vip-manager main loop sleeps before checking for changes. Measured in ms. Defaults to `1000`. Doesn't affect etcd checker since v2.3.0. |
+| `retry-after` | `VIP_RETRY_AFTER` | no | `250` | The time to wait before retrying interactions with components outside of vip-manager. Measured in ms. Defaults to `250`. |
+| `retry-num` | `VIP_RETRY_NUM` | no | `3` | The number of times interactions with components outside of vip-manager are retried. Defaults to `3`. |
+| `etcd-ca-le` | `VIP_ETCD_CA_FILE` | no | `/etc/etcd/ca.cert.pem` | A certificate authority file that can be used to verify the certificate provided by etcd endpoints. Make sure to change `dcs-endpoints` to reflect that `https` is used. |
+| `etcd-cert-le` | `VIP_ETCD_CERT_FILE` | no | `/etc/etcd/client.cert.pem` | A client certificate that is used to authenticate against etcd endpoints. Requires `etcd-ca-file` to be set as well. |
+| `etcd-key-le` | `VIP_ETCD_KEY_FILE` | no | `/etc/etcd/client.key.pem` | A private key for the client certificate, used to decrypt messages sent by etcd endpoints. Required when `etcd-cert-file` is specified. |
+| `verbose` | `VIP_VERBOSE` | no | `true` | Enable more verbose logging. Currently only the manager-type=hetzner provides additional logs. |
## Configuration - Patroni REST API
+
To directly use the Patroni REST API, simply set `dcs-type` to `patroni` and `trigger-key` to `/leader`. The defaults for `dcs-endpoints` (`http://127.0.0.1:8008`) and `trigger-value` (200) for the Patroni checker should work in most cases.
## Configuration - Hetzner
-To use vip-manager with Hetzner Robot API you need a Credential file, set `hosting_type` to `hetzner` in `/etc/default/vip-manager.yml`
+
+To use vip-manager with Hetzner Robot API you need a Credential file, set `hosting_type` to `hetzner` in `/etc/default/vip-manager.yml`
and your Floating-IP must be added on all Servers.
The Floating-IP (VIP) will not be added or removed on the current Master node interface, Hetzner will route it to the current one.
### Credential File - Hetzner
+
Add the File `/etc/hetzner` with your Username and Password
-```
+
+```shell
user="myUsername"
pass="myPassword"
```
@@ -152,13 +171,13 @@ pass="myPassword"
Either:
-* run `vip-manager` with `--verbose` flag or
-* set `verbose` to `true` in `/etc/default/vip-manager.yml`
-* set `VIP_VERBOSE=true`
+- run `vip-manager` with `--verbose` flag or
+- set `verbose` to `true` in `/etc/default/vip-manager.yml`
+- set `VIP_VERBOSE=true`
-> **Note**
+> [!NOTE]
> Currently only supported for `hetzner`
## Author
-CYBERTEC PostgreSQL International GmbH, https://www.cybertec-postgresql.com
+CYBERTEC PostgreSQL International GmbH,
diff --git a/go.mod b/go.mod
index 16d5853..03065cf 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/cybertec-postgresql/vip-manager
go 1.23.0
require (
+ github.com/google/gopacket v1.1.19
github.com/hashicorp/consul/api v1.31.0
github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875
github.com/spf13/pflag v1.0.5
@@ -13,11 +14,11 @@ require (
)
require (
- github.com/armon/go-metrics v0.5.3 // indirect
+ github.com/armon/go-metrics v0.5.4 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
- github.com/fatih/color v1.17.0 // indirect
- github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/fatih/color v1.18.0 // indirect
+ github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -30,8 +31,8 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
github.com/josharian/native v1.1.0 // indirect
- github.com/magiconair/properties v1.8.7 // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/magiconair/properties v1.8.9 // indirect
+ github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 // indirect
github.com/mdlayher/packet v1.1.2 // indirect
@@ -40,23 +41,23 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
- github.com/sagikazarmark/locafero v0.6.0 // indirect
+ github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
- github.com/spf13/afero v1.11.0 // indirect
- github.com/spf13/cast v1.7.0 // indirect
+ github.com/spf13/afero v1.12.0 // indirect
+ github.com/spf13/cast v1.7.1 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.etcd.io/etcd/api/v3 v3.5.17 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.17 // indirect
go.uber.org/multierr v1.11.0 // indirect
- golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
- golang.org/x/net v0.28.0 // indirect
- golang.org/x/sync v0.8.0 // indirect
- golang.org/x/text v0.17.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240823204242-4ba0660f739c // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c // indirect
- google.golang.org/grpc v1.65.0 // indirect
- google.golang.org/protobuf v1.34.2 // indirect
+ golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
+ golang.org/x/net v0.34.0 // indirect
+ golang.org/x/sync v0.10.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect
+ google.golang.org/grpc v1.69.4 // indirect
+ google.golang.org/protobuf v1.36.2 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/go.sum b/go.sum
index f8cf414..c41f339 100644
--- a/go.sum
+++ b/go.sum
@@ -26,10 +26,14 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
+github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
+github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
+github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@@ -54,6 +58,8 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
+github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/hashicorp/consul/api v1.31.0 h1:32BUNLembeSRek0G/ZAM6WNfdEwYdYo8oQ4+JoqGkNQ=
github.com/hashicorp/consul/api v1.31.0/go.mod h1:2ZGIiXM3A610NmDULmCHd/aqBJj8CkMfOhswhOafxRg=
github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg=
@@ -121,6 +127,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
+github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -128,6 +136,8 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
+github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
@@ -193,6 +203,8 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
+github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
+github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
@@ -203,8 +215,12 @@ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9yS
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
+github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
+github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
@@ -243,6 +259,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
+golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
+golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -258,6 +276,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
+golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
+golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -266,6 +286,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -299,6 +321,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -310,12 +334,20 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20240823204242-4ba0660f739c h1:e0zB268kOca6FbuJkYUGxfwG4DKFZG/8DLyv9Zv66cE=
google.golang.org/genproto/googleapis/api v0.0.0-20240823204242-4ba0660f739c/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g=
+google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
+google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c h1:Kqjm4WpoWvwhMPcrAczoTyMySQmYa9Wy2iL6Con4zn8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 h1:3UsHvIr4Wc2aW4brOaSCmcxh9ksica6fHEr8P1XhkYw=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
+google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
+google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/ipmanager/basicConfigurer.go b/ipmanager/basicConfigurer.go
index cef1085..f8cc61c 100644
--- a/ipmanager/basicConfigurer.go
+++ b/ipmanager/basicConfigurer.go
@@ -5,7 +5,9 @@ import (
"net"
"strings"
- arp "github.com/mdlayher/arp"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
)
// BasicConfigurer can be used to enable vip-management on nodes
@@ -16,7 +18,6 @@ import (
// nearby routers and other devices.
type BasicConfigurer struct {
*IPConfiguration
- arpClient *arp.Client
ntecontext uint32 //used by Windows to delete IP address
}
@@ -48,8 +49,51 @@ func (c *BasicConfigurer) queryAddress() bool {
return false
}
-func (c *BasicConfigurer) cleanupArp() {
- if c.arpClient != nil {
- c.arpClient.Close()
+const (
+ MACAddressSize = 6
+ IPv4AddressSize = 4
+)
+
+// arpSendGratuitous is a function that sends gratuitous ARP requests
+func (c *BasicConfigurer) arpSendGratuitous() error {
+ // Open the network interface for sending
+ handle, err := pcap.OpenLive(c.Iface.Name, 65536, false, pcap.BlockForever)
+ if err != nil {
+ return err
+ }
+ defer handle.Close()
+
+ // Create the Ethernet layer
+ ethLayer := &layers.Ethernet{
+ SrcMAC: c.Iface.HardwareAddr,
+ DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // Broadcast
+ EthernetType: layers.EthernetTypeARP,
+ }
+
+ // Create the ARP layer
+ arpLayer := &layers.ARP{
+ AddrType: layers.LinkTypeEthernet,
+ Protocol: layers.EthernetTypeIPv4,
+ HwAddressSize: MACAddressSize,
+ ProtAddressSize: IPv4AddressSize,
+ Operation: layers.ARPReply, // Gratuitous ARP is sent as a reply
+ SourceHwAddress: c.Iface.HardwareAddr,
+ SourceProtAddress: c.IPConfiguration.VIP.AsSlice(),
+ DstHwAddress: c.Iface.HardwareAddr, // Gratuitous ARP targets itself
+ DstProtAddress: c.IPConfiguration.VIP.AsSlice(),
+ }
+
+ // Create a packet with the layers
+ buffer := gopacket.NewSerializeBuffer()
+ opts := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
}
+ err = gopacket.SerializeLayers(buffer, opts, ethLayer, arpLayer)
+ if err != nil {
+ return err
+ }
+
+ // Send the packet
+ return handle.WritePacketData(buffer.Bytes())
}
diff --git a/ipmanager/basicConfigurer_linux.go b/ipmanager/basicConfigurer_linux.go
index 342320b..7337a14 100644
--- a/ipmanager/basicConfigurer_linux.go
+++ b/ipmanager/basicConfigurer_linux.go
@@ -1,11 +1,7 @@
package ipmanager
import (
- "net"
"os/exec"
- "time"
-
- arp "github.com/mdlayher/arp"
)
const (
@@ -13,27 +9,14 @@ const (
arpReplyOp = 2
)
-var (
- ethernetBroadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
-)
-
// configureAddress assigns virtual IP address
func (c *BasicConfigurer) configureAddress() bool {
- if c.arpClient == nil {
- if err := c.createArpClient(); err != nil {
- log.Error("Couldn't create an Arp client:", err)
- }
- }
-
log.Infof("Configuring address %s on %s", c.getCIDR(), c.Iface.Name)
-
result := c.runAddressConfiguration("add")
-
if result {
- // For now it is save to say that also working even if a
- // gratuitous arp message could not be send but logging an
- // errror should be enough.
- _ = c.arpSendGratuitous()
+ if err := c.arpSendGratuitous(); err != nil {
+ log.Error("Failed to send gratuitous ARP: ", err)
+ }
}
return result
@@ -64,96 +47,3 @@ func (c *BasicConfigurer) runAddressConfiguration(action string) bool {
}
return true
}
-
-func (c *BasicConfigurer) createArpClient() (err error) {
- for i := 0; i < c.RetryNum; i++ {
- if c.arpClient, err = arp.Dial(&c.Iface); err == nil {
- return
- }
- log.Infof("Problems with producing the arp client: %s", err)
- time.Sleep(time.Duration(c.RetryAfter) * time.Millisecond)
- }
- return
-}
-
-// sends a gratuitous ARP request and reply
-func (c *BasicConfigurer) arpSendGratuitous() error {
- /* While RFC 2002 does not say whether a gratuitous ARP request or reply is preferred
- * to update ones neighbours' MAC tables, the Wireshark Wiki recommends sending both.
- * https://wiki.wireshark.org/Gratuitous_ARP
- * This site also recommends sending a reply, as requests might be ignored by some hardware:
- * https://support.citrix.com/article/CTX112701
- */
- if c.arpClient == nil {
- log.Info("No arp client available, skip send gratuitous ARP")
- return nil
- }
- gratuitousReplyPackage, err := arp.NewPacket(
- arpReplyOp,
- c.Iface.HardwareAddr,
- c.VIP,
- c.Iface.HardwareAddr,
- c.VIP,
- )
- if err != nil {
- log.Infof("Gratuitous arp reply package is malformed: %s", err)
- return err
- }
-
- /* RFC 2002 specifies (in section 4.6) that a gratuitous ARP request
- * should "not set" the target Hardware Address (THA).
- * Since the arp package offers no option to leave the THA out, we specify the Zero-MAC.
- * If parsing that fails for some reason, we'll just use the local interface's address.
- * The field is probably ignored by the receivers' implementation anyway.
- */
- arpRequestDestMac, err := net.ParseMAC("00:00:00:00:00:00")
- if err != nil {
- // not entirely RFC-2002 conform but better then nothing.
- arpRequestDestMac = c.Iface.HardwareAddr
- }
-
- gratuitousRequestPackage, err := arp.NewPacket(
- arpRequestOp,
- c.Iface.HardwareAddr,
- c.VIP,
- arpRequestDestMac,
- c.VIP,
- )
- if err != nil {
- log.Infof("Gratuitous arp request package is malformed: %s", err)
- return err
- }
-
- for i := 0; i < c.RetryNum; i++ {
- errReply := c.arpClient.WriteTo(gratuitousReplyPackage, ethernetBroadcast)
- if err != nil {
- log.Error("Couldn't write to the arpClient:", errReply)
- } else {
- log.Info("Sent gratuitous ARP reply")
- }
-
- errRequest := c.arpClient.WriteTo(gratuitousRequestPackage, ethernetBroadcast)
- if err != nil {
- log.Error("Couldn't write to the arpClient:", errRequest)
- } else {
- log.Info("Sent gratuitous ARP request")
- }
-
- if errReply != nil || errRequest != nil {
- /* If something went wrong while sending the packages, we'll recreate the ARP client for the next try,
- * to avoid having a stale client that gives "network is down" error.
- */
- err = c.createArpClient()
- } else {
- //TODO: think about whether to leave this out to achieve simple repeat sending of GARP packages
- break
- }
- time.Sleep(time.Duration(c.RetryAfter) * time.Millisecond)
- }
- if err != nil {
- log.Error("Too many retries", err)
- return err
- }
-
- return nil
-}
diff --git a/ipmanager/basicConfigurer_windows.go b/ipmanager/basicConfigurer_windows.go
index fb6bd6f..50609f7 100644
--- a/ipmanager/basicConfigurer_windows.go
+++ b/ipmanager/basicConfigurer_windows.go
@@ -25,10 +25,10 @@ func (c *BasicConfigurer) configureAddress() bool {
log.Error("Failed to add address: ", err)
return false
}
- // For now it is save to say that also working even if a
- // gratuitous arp message could not be send but logging an
- // errror should be enough.
- //_ = c.ARPSendGratuitous()
+
+ if err := c.arpSendGratuitous(); err != nil {
+ log.Error("Failed to send gratuitous ARP: ", err)
+ }
return true
}
diff --git a/ipmanager/hetznerConfigurer.go b/ipmanager/hetznerConfigurer.go
index da1d9ce..1c00b99 100644
--- a/ipmanager/hetznerConfigurer.go
+++ b/ipmanager/hetznerConfigurer.go
@@ -275,8 +275,3 @@ func (c *HetznerConfigurer) runAddressConfiguration() bool {
c.cachedState = unknown
return false
}
-
-func (c *HetznerConfigurer) cleanupArp() {
- // dummy function as the usage of interfaces requires us to have this function.
- // It is sufficient for the leader to tell Hetzner to switch the IP, no cleanup needed.
-}
diff --git a/ipmanager/ip_manager.go b/ipmanager/ip_manager.go
index 66f6242..97a4143 100644
--- a/ipmanager/ip_manager.go
+++ b/ipmanager/ip_manager.go
@@ -16,7 +16,6 @@ type ipConfigurer interface {
configureAddress() bool
deconfigureAddress() bool
getCIDR() string
- cleanupArp()
}
var log *zap.SugaredLogger = zap.L().Sugar()
@@ -124,7 +123,6 @@ func (m *IPManager) SyncStates(ctx context.Context, states <-chan bool) {
}
case <-ctx.Done():
m.configurer.deconfigureAddress()
- m.configurer.cleanupArp()
return
}
}