mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/kube-vip/kube-vip.git
synced 2026-09-20 08:03:47 +08:00
Added MP-BGP for IPv4 over IPv6 session and config flags
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
This commit is contained in:
@@ -60,7 +60,7 @@ func main() {
|
||||
fmt.Println("error: ", err)
|
||||
}
|
||||
|
||||
ServerConn.WriteTo(buf[0:n])
|
||||
ServerConn.WriteTo(buf[0:n], addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
276
pkg/bgp/peers.go
276
pkg/bgp/peers.go
@@ -7,10 +7,12 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/ptypes" //nolint
|
||||
//nolint
|
||||
"github.com/golang/protobuf/ptypes/any"
|
||||
"github.com/kube-vip/kube-vip/pkg/vip"
|
||||
api "github.com/osrg/gobgp/v3/api"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/osrg/gobgp/v3/pkg/server"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
)
|
||||
|
||||
// AddPeer will add peers to the BGP configuration
|
||||
@@ -41,8 +43,10 @@ func (b *Server) AddPeer(peer Peer) (err error) {
|
||||
RemoteAddress: peer.Address,
|
||||
RemotePort: uint32(179),
|
||||
},
|
||||
}
|
||||
|
||||
AfiSafis: []*api.AfiSafi{
|
||||
if b.c.MpbgpNexthop != "" {
|
||||
p.AfiSafis = []*api.AfiSafi{
|
||||
{
|
||||
Config: &api.AfiSafiConfig{
|
||||
Family: &api.Family{
|
||||
@@ -61,120 +65,51 @@ func (b *Server) AddPeer(peer Peer) (err error) {
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var ipv6Address *string
|
||||
|
||||
if b.c.SourceIP != "" {
|
||||
p.Transport.LocalAddress = b.c.SourceIP
|
||||
|
||||
// Resolve the local interface by SourceIP
|
||||
iface, err := GetInterfaceByIP(b.c.SourceIP)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get interface by IP: %v", err)
|
||||
}
|
||||
|
||||
// Get the non link-local IPv6 address on that interface
|
||||
ipv6, err := GetNonLinkLocalIPv6(iface)
|
||||
peer.setMpbgpOptions(b.c)
|
||||
|
||||
ipv4Address, ipv6Address, err := peer.findMpbgpAddresses(p, b.c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get non link-local IPv6 address: %v", err)
|
||||
return fmt.Errorf("failed to get MP-BGP addresses: %w", err)
|
||||
}
|
||||
|
||||
ipv6Address = &ipv6
|
||||
}
|
||||
|
||||
if b.c.SourceIF != "" {
|
||||
p.Transport.BindInterface = b.c.SourceIF
|
||||
|
||||
iface, err := net.InterfaceByName(b.c.SourceIF)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get interface by name: %v", err)
|
||||
mask := "128"
|
||||
address := ipv4Address
|
||||
family := api.Family_AFI_IP
|
||||
if vip.IsIPv4(p.Conf.NeighborAddress) {
|
||||
mask = "32"
|
||||
address = ipv6Address
|
||||
family = api.Family_AFI_IP6
|
||||
}
|
||||
|
||||
// Get the non link-local IPv6 address on that interface
|
||||
ipv6, err := GetNonLinkLocalIPv6(iface)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get non link-local IPv6 address: %v", err)
|
||||
}
|
||||
|
||||
ipv6Address = &ipv6
|
||||
}
|
||||
|
||||
if ipv6Address != nil {
|
||||
err := b.s.AddDefinedSet(context.Background(), &api.AddDefinedSetRequest{
|
||||
err = b.s.AddDefinedSet(context.Background(), &api.AddDefinedSetRequest{
|
||||
DefinedSet: &api.DefinedSet{
|
||||
DefinedType: api.DefinedType_NEIGHBOR,
|
||||
Name: fmt.Sprintf("peer-%s", p.Conf.NeighborAddress),
|
||||
List: []string{fmt.Sprintf("%s/32", p.Conf.NeighborAddress)},
|
||||
List: []string{fmt.Sprintf("%s/%s", p.Conf.NeighborAddress, mask)},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add defined set: %v", err)
|
||||
}
|
||||
|
||||
err = b.s.AddPolicy(context.Background(), &api.AddPolicyRequest{
|
||||
Policy: &api.Policy{
|
||||
Name: fmt.Sprintf("peer-%s", p.Conf.NeighborAddress),
|
||||
Statements: []*api.Statement{
|
||||
{
|
||||
Conditions: &api.Conditions{
|
||||
AfiSafiIn: []*api.Family{
|
||||
{
|
||||
Afi: api.Family_AFI_IP6,
|
||||
Safi: api.Family_SAFI_UNICAST,
|
||||
},
|
||||
},
|
||||
NeighborSet: &api.MatchSet{
|
||||
Type: api.MatchSet_ANY,
|
||||
Name: fmt.Sprintf("peer-%s", p.Conf.NeighborAddress),
|
||||
},
|
||||
},
|
||||
Actions: &api.Actions{
|
||||
RouteAction: api.RouteAction_ACCEPT,
|
||||
Nexthop: &api.NexthopAction{
|
||||
Address: *ipv6Address,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Conditions: &api.Conditions{
|
||||
NeighborSet: &api.MatchSet{
|
||||
Type: api.MatchSet_ANY,
|
||||
Name: fmt.Sprintf("peer-%s", p.Conf.NeighborAddress),
|
||||
},
|
||||
},
|
||||
Actions: &api.Actions{
|
||||
RouteAction: api.RouteAction_ACCEPT,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add policy: %v", err)
|
||||
if address != "" {
|
||||
if err := insertPolicy(b.s, address, p, family); err != nil {
|
||||
return fmt.Errorf("failed to add policy: %w", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if b.c.SourceIP != "" {
|
||||
p.Transport.LocalAddress = b.c.SourceIP
|
||||
}
|
||||
|
||||
err = b.s.AddPolicyAssignment(context.Background(), &api.AddPolicyAssignmentRequest{
|
||||
Assignment: &api.PolicyAssignment{
|
||||
Name: "global",
|
||||
Direction: api.PolicyDirection_EXPORT,
|
||||
Policies: []*api.Policy{
|
||||
{
|
||||
Name: fmt.Sprintf("peer-%s", p.Conf.NeighborAddress),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add policy assignment: %v", err)
|
||||
if b.c.SourceIF != "" {
|
||||
p.Transport.BindInterface = b.c.SourceIF
|
||||
}
|
||||
}
|
||||
|
||||
err = b.s.AddPeer(context.Background(), &api.AddPeerRequest{
|
||||
Peer: p,
|
||||
})
|
||||
if err != nil {
|
||||
if err := b.s.AddPeer(context.Background(), &api.AddPeerRequest{Peer: p}); err != nil {
|
||||
return fmt.Errorf("failed to add peer: %v", err)
|
||||
}
|
||||
|
||||
@@ -185,19 +120,19 @@ func (b *Server) getPath(ip net.IP) (path *api.Path) {
|
||||
isV6 := ip.To4() == nil
|
||||
|
||||
//nolint
|
||||
originAttr, _ := ptypes.MarshalAny(&api.OriginAttribute{
|
||||
originAttr, _ := anypb.New(&api.OriginAttribute{
|
||||
Origin: 0,
|
||||
})
|
||||
|
||||
if !isV6 {
|
||||
//nolint
|
||||
nlri, _ := ptypes.MarshalAny(&api.IPAddressPrefix{
|
||||
nlri, _ := anypb.New(&api.IPAddressPrefix{
|
||||
Prefix: ip.String(),
|
||||
PrefixLen: 32,
|
||||
})
|
||||
|
||||
//nolint
|
||||
nhAttr, _ := ptypes.MarshalAny(&api.NextHopAttribute{
|
||||
nhAttr, _ := anypb.New(&api.NextHopAttribute{
|
||||
NextHop: "0.0.0.0", // gobgp will fill this
|
||||
})
|
||||
|
||||
@@ -211,7 +146,7 @@ func (b *Server) getPath(ip net.IP) (path *api.Path) {
|
||||
}
|
||||
} else {
|
||||
//nolint
|
||||
nlri, _ := ptypes.MarshalAny(&api.IPAddressPrefix{
|
||||
nlri, _ := anypb.New(&api.IPAddressPrefix{
|
||||
Prefix: ip.String(),
|
||||
PrefixLen: 128,
|
||||
})
|
||||
@@ -222,7 +157,7 @@ func (b *Server) getPath(ip net.IP) (path *api.Path) {
|
||||
}
|
||||
|
||||
//nolint
|
||||
mpAttr, _ := ptypes.MarshalAny(&api.MpReachNLRIAttribute{
|
||||
mpAttr, _ := anypb.New(&api.MpReachNLRIAttribute{
|
||||
Family: v6Family,
|
||||
NextHops: []string{"::"}, // gobgp will fill this
|
||||
Nlris: []*any.Any{nlri},
|
||||
@@ -241,11 +176,13 @@ func (b *Server) getPath(ip net.IP) (path *api.Path) {
|
||||
func ParseBGPPeerConfig(config string) (bgpPeers []Peer, err error) {
|
||||
peers := strings.Split(config, ",")
|
||||
if len(peers) == 0 {
|
||||
return nil, fmt.Errorf("No BGP Peer configurations found")
|
||||
return nil, fmt.Errorf("no BGP Peer configurations found")
|
||||
}
|
||||
|
||||
for x := range peers {
|
||||
peerStr := peers[x]
|
||||
config := strings.Split(peerStr, "/")
|
||||
peerStr = config[0]
|
||||
if peerStr == "" {
|
||||
continue
|
||||
}
|
||||
@@ -288,11 +225,33 @@ func ParseBGPPeerConfig(config string) (bgpPeers []Peer, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
var mpbgpNexthop, mpbgpIPv4, mpbgpIPv6 string
|
||||
|
||||
if len(config) > 1 {
|
||||
configData := strings.Split(config[1], ";")
|
||||
for _, cfg := range configData {
|
||||
c := strings.Split(cfg, "=")
|
||||
switch c[0] {
|
||||
case "mpbgp_nexthop":
|
||||
mpbgpNexthop = c[1]
|
||||
case "mpbgp_ipv4":
|
||||
mpbgpIPv4 = c[1]
|
||||
case "mpbgp_ipv6":
|
||||
mpbgpIPv6 = c[1]
|
||||
default:
|
||||
return nil, fmt.Errorf("peer configuration parameter '%s' is not supported", c[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peerConfig := Peer{
|
||||
Address: address,
|
||||
AS: uint32(ASNumber),
|
||||
Password: password,
|
||||
MultiHop: multiHop,
|
||||
Address: address,
|
||||
AS: uint32(ASNumber),
|
||||
Password: password,
|
||||
MultiHop: multiHop,
|
||||
MpbgpNexthop: mpbgpNexthop,
|
||||
MpbgpIPv4: mpbgpIPv4,
|
||||
MpbgpIPv6: mpbgpIPv6,
|
||||
}
|
||||
|
||||
bgpPeers = append(bgpPeers, peerConfig)
|
||||
@@ -300,56 +259,73 @@ func ParseBGPPeerConfig(config string) (bgpPeers []Peer, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// GetInterfaceByIP returns the network interface that has the specified IP address assigned.
|
||||
func GetInterfaceByIP(ipAddr string) (*net.Interface, error) {
|
||||
ip := net.ParseIP(ipAddr)
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("invalid IP address: %s", ipAddr)
|
||||
func insertPolicy(s *server.BgpServer, address string, p *api.Peer, family api.Family_Afi) error {
|
||||
familyType := "v4"
|
||||
if family == api.Family_AFI_IP6 {
|
||||
familyType = "v6"
|
||||
}
|
||||
|
||||
links, err := netlink.LinkList()
|
||||
setName := fmt.Sprintf("peer-%s", p.Conf.NeighborAddress)
|
||||
policyName := fmt.Sprintf("%s-%s", setName, familyType)
|
||||
|
||||
policy := &api.Policy{
|
||||
Name: policyName,
|
||||
Statements: []*api.Statement{
|
||||
{
|
||||
Conditions: &api.Conditions{
|
||||
AfiSafiIn: []*api.Family{
|
||||
{
|
||||
Afi: family,
|
||||
Safi: api.Family_SAFI_UNICAST,
|
||||
},
|
||||
},
|
||||
NeighborSet: &api.MatchSet{
|
||||
Type: api.MatchSet_ANY,
|
||||
Name: setName,
|
||||
},
|
||||
},
|
||||
Actions: &api.Actions{
|
||||
RouteAction: api.RouteAction_ACCEPT,
|
||||
Nexthop: &api.NexthopAction{
|
||||
Address: address,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Conditions: &api.Conditions{
|
||||
NeighborSet: &api.MatchSet{
|
||||
Type: api.MatchSet_ANY,
|
||||
Name: setName,
|
||||
},
|
||||
},
|
||||
Actions: &api.Actions{
|
||||
RouteAction: api.RouteAction_ACCEPT,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := s.AddPolicy(context.Background(), &api.AddPolicyRequest{
|
||||
Policy: policy,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list network interfaces: %v", err)
|
||||
return fmt.Errorf("failed to add policy: %w", err)
|
||||
}
|
||||
|
||||
for _, link := range links {
|
||||
addrs, err := netlink.AddrList(link, netlink.FAMILY_ALL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list addresses for interface %s: %v", link.Attrs().Name, err)
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
if addr.IP.Equal(ip) {
|
||||
iface, err := net.InterfaceByIndex(link.Attrs().Index)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get interface by index: %v", err)
|
||||
}
|
||||
return iface, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no interface found with IP address: %s", ipAddr)
|
||||
}
|
||||
|
||||
// GetNonLinkLocalIPv6 returns the first non link-local IPv6 address on the given interface.
|
||||
func GetNonLinkLocalIPv6(iface *net.Interface) (string, error) {
|
||||
addrs, err := iface.Addrs()
|
||||
err = s.AddPolicyAssignment(context.Background(), &api.AddPolicyAssignmentRequest{
|
||||
Assignment: &api.PolicyAssignment{
|
||||
Name: "global",
|
||||
Direction: api.PolicyDirection_EXPORT,
|
||||
Policies: []*api.Policy{
|
||||
{
|
||||
Name: policy.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to list addresses for interface %s: %v", iface.Name, err)
|
||||
return fmt.Errorf("failed to add policy assignment: %v", err)
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
ipNet, ok := addr.(*net.IPNet)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
ip := ipNet.IP
|
||||
if ip.To4() == nil && !ip.IsLinkLocalUnicast() {
|
||||
return ip.String(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no non link-local IPv6 address found on interface %s", iface.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,15 +13,15 @@ import (
|
||||
// NewBGPServer takes a configuration and returns a running BGP server instance
|
||||
func NewBGPServer(c *Config, peerStateChangeCallback func(*api.WatchEventResponse_PeerEvent)) (b *Server, err error) {
|
||||
if c.AS == 0 {
|
||||
return nil, fmt.Errorf("You need to provide AS")
|
||||
return nil, fmt.Errorf("you need to provide AS")
|
||||
}
|
||||
|
||||
if c.SourceIP != "" && c.SourceIF != "" {
|
||||
return nil, fmt.Errorf("SourceIP and SourceIF are mutually exclusive")
|
||||
return nil, fmt.Errorf("sourceIP and SourceIF are mutually exclusive")
|
||||
}
|
||||
|
||||
if len(c.Peers) == 0 {
|
||||
return nil, fmt.Errorf("You need to provide at least one peer")
|
||||
return nil, fmt.Errorf("you need to provide at least one peer")
|
||||
}
|
||||
|
||||
b = &Server{
|
||||
|
||||
117
pkg/bgp/types.go
117
pkg/bgp/types.go
@@ -1,21 +1,120 @@
|
||||
package bgp
|
||||
|
||||
import gobgp "github.com/osrg/gobgp/v3/pkg/server"
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/kube-vip/kube-vip/pkg/vip"
|
||||
api "github.com/osrg/gobgp/v3/api"
|
||||
gobgp "github.com/osrg/gobgp/v3/pkg/server"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// Peer defines a BGP Peer
|
||||
type Peer struct {
|
||||
Address string
|
||||
AS uint32
|
||||
Password string
|
||||
MultiHop bool
|
||||
Address string
|
||||
AS uint32
|
||||
Password string
|
||||
MultiHop bool
|
||||
MpbgpNexthop string
|
||||
MpbgpIPv4 string
|
||||
MpbgpIPv6 string
|
||||
}
|
||||
|
||||
func (p *Peer) setMpbgpOptions(server *Config) {
|
||||
if p.MpbgpNexthop == "" {
|
||||
p.MpbgpNexthop = server.MpbgpNexthop
|
||||
}
|
||||
|
||||
if p.MpbgpIPv4 == "" {
|
||||
p.MpbgpIPv4 = server.MpbgpIPv4
|
||||
}
|
||||
|
||||
if p.MpbgpIPv6 == "" {
|
||||
p.MpbgpIPv6 = server.MpbgpIPv6
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Peer) findMpbgpAddresses(ap *api.Peer, server *Config) (string, string, error) {
|
||||
var ipv4Address, ipv6Address string
|
||||
switch p.MpbgpNexthop {
|
||||
case "fixed":
|
||||
ap.Transport.LocalAddress = server.SourceIP
|
||||
if p.MpbgpIPv4 == "" && p.MpbgpIPv6 == "" {
|
||||
return "", "", fmt.Errorf("to use MP-BGP with fixed address at least one IPv4 or IPv6 address has to be provided [current - IPv4: %s, IPv6: %s]",
|
||||
p.MpbgpIPv4, p.MpbgpIPv6)
|
||||
}
|
||||
|
||||
if p.MpbgpIPv4 != "" {
|
||||
if net.ParseIP(p.MpbgpIPv4) == nil {
|
||||
return "", "", fmt.Errorf("provided address '%s' is not a valid IPv4 address", p.MpbgpIPv4)
|
||||
}
|
||||
}
|
||||
if p.MpbgpIPv6 != "" {
|
||||
if net.ParseIP(p.MpbgpIPv6) == nil {
|
||||
return "", "", fmt.Errorf("provided address '%s' is not a valid IPv6 address", p.MpbgpIPv6)
|
||||
}
|
||||
}
|
||||
|
||||
ipv4Address = p.MpbgpIPv4
|
||||
ipv6Address = p.MpbgpIPv6
|
||||
case "auto_sourceip":
|
||||
ap.Transport.LocalAddress = server.SourceIP
|
||||
|
||||
// Resolve the local interface by SourceIP
|
||||
iface, err := vip.GetInterfaceByIP(server.SourceIP)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get interface by IP: %v", err)
|
||||
}
|
||||
|
||||
if vip.IsIPv4(server.SourceIP) {
|
||||
// Get the non link-local IPv6 address on that interface
|
||||
ipv6Address, err = vip.GetNonLinkLocalIP(iface, netlink.FAMILY_V6)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get non link-local IPv6 address: %v", err)
|
||||
}
|
||||
} else {
|
||||
// Get the non link-local IPv4 address on that interface
|
||||
ipv4Address, err = vip.GetNonLinkLocalIP(iface, netlink.FAMILY_V4)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get non link-local IPv4 address: %v", err)
|
||||
}
|
||||
}
|
||||
case "auto_sourceif":
|
||||
ap.Transport.BindInterface = server.SourceIF
|
||||
|
||||
iface, err := netlink.LinkByName(server.SourceIF)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get interface by name: %v", err)
|
||||
}
|
||||
|
||||
// Get the non link-local IPv4 address on that interface
|
||||
ipv4Address, err = vip.GetNonLinkLocalIP(&iface, netlink.FAMILY_V4)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get non link-local IPv4 address: %v", err)
|
||||
}
|
||||
|
||||
// Get the non link-local IPv6 address on that interface
|
||||
ipv6Address, err = vip.GetNonLinkLocalIP(&iface, netlink.FAMILY_V6)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to get non link-local IPv6 address: %v", err)
|
||||
}
|
||||
default:
|
||||
return "", "", fmt.Errorf("option %s for MP-BPG nexthop is not supported", server.MpbgpNexthop)
|
||||
}
|
||||
|
||||
return ipv4Address, ipv6Address, nil
|
||||
}
|
||||
|
||||
// Config defines the BGP server configuration
|
||||
type Config struct {
|
||||
AS uint32
|
||||
RouterID string
|
||||
SourceIP string
|
||||
SourceIF string
|
||||
AS uint32
|
||||
RouterID string
|
||||
SourceIP string
|
||||
SourceIF string
|
||||
MpbgpNexthop string
|
||||
MpbgpIPv4 string
|
||||
MpbgpIPv6 string
|
||||
|
||||
HoldTime uint64
|
||||
KeepaliveInterval uint64
|
||||
|
||||
@@ -444,6 +444,24 @@ func ParseEnvironment(c *Config) error {
|
||||
c.BGPConfig.Peers = peers
|
||||
}
|
||||
|
||||
// MPBGP mode
|
||||
env = os.Getenv(mpbgpNexthop)
|
||||
if env != "" {
|
||||
c.BGPConfig.MpbgpNexthop = env
|
||||
}
|
||||
|
||||
// MPBGP fixed IPv4
|
||||
env = os.Getenv(mpbgpIPv4)
|
||||
if env != "" {
|
||||
c.BGPConfig.MpbgpIPv4 = env
|
||||
}
|
||||
|
||||
// MPBGP fixed IPv6
|
||||
env = os.Getenv(mpbgpIPv6)
|
||||
if env != "" {
|
||||
c.BGPConfig.MpbgpIPv6 = env
|
||||
}
|
||||
|
||||
// BGP Peer mutlihop
|
||||
env = os.Getenv(bgpMultiHop)
|
||||
if env != "" {
|
||||
|
||||
@@ -125,6 +125,13 @@ const (
|
||||
// bgpKeepaliveInterval defines bgp timers keepalive interval
|
||||
bgpKeepaliveInterval = "bgp_keepalive_interval"
|
||||
|
||||
// mpbgpNexthop defines MPBGP mode
|
||||
mpbgpNexthop = "mpbgp_nexthop"
|
||||
// mpbgpIPv4 defines fixed IPv4 to be used with MPBGP
|
||||
mpbgpIPv4 = "mpbgp_ipv4"
|
||||
// mpbgpIPv6 defines fixed IPv6 to be used with MPBGP
|
||||
mpbgpIPv6 = "mpbgp_ipv6"
|
||||
|
||||
// vipWireguard - defines if wireguard will be used for vips
|
||||
vipWireguard = "vip_wireguard" //nolint
|
||||
|
||||
|
||||
@@ -202,3 +202,50 @@ func Split(values string) []string {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// GetInterfaceByIP returns the network interface that has the specified IP address assigned.
|
||||
func GetInterfaceByIP(ipAddr string) (*netlink.Link, error) {
|
||||
ip := net.ParseIP(ipAddr)
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("invalid IP address: %s", ipAddr)
|
||||
}
|
||||
|
||||
links, err := netlink.LinkList()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list network interfaces: %v", err)
|
||||
}
|
||||
|
||||
for i := range links {
|
||||
addrs, err := netlink.AddrList(links[i], netlink.FAMILY_ALL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list addresses for interface %s: %v", links[i].Attrs().Name, err)
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
if addr.IP.Equal(ip) {
|
||||
return &links[i], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no interface found with IP address: %s", ipAddr)
|
||||
}
|
||||
|
||||
// GetNonLinkLocalIP returns the first non link-local IPv4/IPv6 address on the given interface.
|
||||
func GetNonLinkLocalIP(iface *netlink.Link, family int) (string, error) {
|
||||
a, err := netlink.AddrList(*iface, family)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to list addresses for interface %s: %v", (*iface).Attrs().Name, err)
|
||||
}
|
||||
|
||||
for _, addr := range a {
|
||||
if addr.IPNet != nil {
|
||||
ip := addr.IPNet.IP
|
||||
if !ip.IsLinkLocalUnicast() {
|
||||
return ip.String(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("failed to find non-local IP on interface: %s", (*iface).Attrs().Name)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user