Skip to content

Commit

Permalink
Ensure kernel sends GARPs to avoid communication failures (#4649)
Browse files Browse the repository at this point in the history
Signed-off-by: Cyclinder Kuo <[email protected]>
  • Loading branch information
cyclinder authored Feb 14, 2025
1 parent 742781e commit f8f971d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
28 changes: 26 additions & 2 deletions cmd/spiderpool/cmd/command_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/spidernet-io/spiderpool/api/v1/agent/models"
"github.com/spidernet-io/spiderpool/pkg/constant"
spiderpoolip "github.com/spidernet-io/spiderpool/pkg/ip"
"github.com/spidernet-io/spiderpool/pkg/networking/networking"
"github.com/spidernet-io/spiderpool/pkg/openapi"
)

Expand Down Expand Up @@ -164,8 +165,7 @@ func CmdAdd(args *skel.CmdArgs) (err error) {
// do ip conflict and gateway detection
logger.Sugar().Info("postIpam response",
zap.Any("DNS", ipamResponse.Payload.DNS),
zap.Any("Routes", ipamResponse.Payload.Routes),
zap.Any("Ips", ipamResponse.Payload.Ips))
zap.Any("Routes", ipamResponse.Payload.Routes))

if err = DetectIPConflictAndGatewayReachable(logger, args.IfName, hostNs, netns, ipamResponse.Payload.Ips); err != nil {
if errors.Is(err, constant.ErrIPConflict) || errors.Is(err, constant.ErrGatewayUnreachable) {
Expand All @@ -179,6 +179,30 @@ func CmdAdd(args *skel.CmdArgs) (err error) {
return err
}

// CNI will set the interface to up, and the kernel only sends GARPs/Unsolicited NA when the interface
// goes from down to up or when the link-layer address changes on the interfaces. in order to the
// kernel send GARPs/Unsolicited NA when the interface goes from down to up.
// see https://github.com/spidernet-io/spiderpool/issues/4650
var ipRes []net.IP
for _, i := range ipamResponse.Payload.Ips {
if i.Address != nil && *i.Address != "" {
ipa, _, err := net.ParseCIDR(*i.Address)
if err != nil {
logger.Error(err.Error())
continue
}
ipRes = append(ipRes, ipa)
}
}

err = netns.Do(func(netNS ns.NetNS) error {
return networking.AnnounceIPs(logger, args.IfName, ipRes)
})

if err != nil {
logger.Error(err.Error())
}

// Assemble the result of IPAM request response.
result, err := assembleResult(conf.CNIVersion, args.IfName, ipamResponse)
if err != nil {
Expand Down
37 changes: 37 additions & 0 deletions pkg/networking/networking/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"syscall"
"time"

"go.uber.org/zap"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv6"
"golang.org/x/sys/unix"
Expand Down Expand Up @@ -313,3 +314,39 @@ func ParseIPv6NeighborAdvertisementMsg(n int, buf []byte) (srcIP net.IP, mac net
}
return
}

func AnnounceIPs(logger *zap.Logger, iface string, ips []net.IP) error {
l, err := netlink.LinkByName(iface)
if err != nil {
return err
}

for _, addr := range ips {
logger.Debug("announcing ip", zap.String("ip", addr.String()), zap.String("interface", iface))
if addr.To4() != nil {
// send an gratuitous arp to announce the new mac address
if err = SendARPReuqest(l, addr, addr); err != nil {
logger.Error("failed to send gratuitous arps", zap.Error(err))
} else {
logger.Info("Send gratuitous arps successfully", zap.String("interface", iface))
}
} else {
ifi, err := net.InterfaceByName(iface)
if err != nil {
return fmt.Errorf("failed to InterfaceByName %s: %w", iface, err)
}

ndpClient, _, err := ndp.Listen(ifi, ndp.LinkLocal)
if err != nil {
return fmt.Errorf("failed to init ndp client: %w", err)
}
defer ndpClient.Close()
if err = SendUnsolicitedNeighborAdvertisement(addr, ifi, ndpClient); err != nil {
logger.Error("failed to send unsolicited neighbor advertisements", zap.Error(err))
} else {
logger.Info("Send unsolicited neighbor advertisements successfully", zap.String("interface", iface))
}
}
}
return nil
}

0 comments on commit f8f971d

Please sign in to comment.