From 645b10548ae1dd3273592e44c2f368ecf4fb2c67 Mon Sep 17 00:00:00 2001 From: mgaitonde Date: Fri, 18 Aug 2023 16:23:47 -0700 Subject: [PATCH] ipv6 support wip --- config.yaml | 6 ++++++ config/config.go | 4 +++- controller/bgp.go | 20 +++++++++++++++----- controller/system.go | 34 +++++++++++++++++++++++++++------- 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/config.yaml b/config.yaml index f94aec0..2e8c7cc 100644 --- a/config.yaml +++ b/config.yaml @@ -21,6 +21,12 @@ bgp: - asn:nnnn - asn:nnnn origin: igp + # family will determine whether we want to peer over an ipv4 or ipv6 session + # one gocast instance can only peer over one session. Multiple sessions are not + # supported. The default is 4 + family: 4 + # router ID is required when family 6 is specified + router_id: 1.1.1.1 # optional list of apps to register on startup apps: diff --git a/config/config.go b/config/config.go index 8947c49..ffdd404 100644 --- a/config/config.go +++ b/config/config.go @@ -15,7 +15,7 @@ type AgentConfig struct { CleanupTimer time.Duration `yaml:"cleanup_timer"` ConsulAddr string `yaml:"consul_addr"` ConsulQueryInterval time.Duration `yaml:"consul_query_interval"` - ConsulToken string `yaml:"consul_token"` + ConsulToken string `yaml:"consul_token"` } type BgpConfig struct { @@ -25,6 +25,8 @@ type BgpConfig struct { PeerIP string `yaml:"peer_ip"` Communities []string Origin string + Family int + RouterID string `yaml:"router_id"` } type VipConfig struct { diff --git a/controller/bgp.go b/controller/bgp.go index 96da20d..94741e5 100644 --- a/controller/bgp.go +++ b/controller/bgp.go @@ -32,10 +32,13 @@ func NewController(config c.BgpConfig) (*Controller, error) { c := &Controller{} var gw net.IP var err error + if config.Family == 0 { + config.Family = 4 + } if config.PeerIP == "" { - gw, err := gateway() + gw, err := gateway(config.Family) if err != nil { - return nil, fmt.Errorf("Unable to get gw ip: %v", err) + return nil, fmt.Errorf("unable to get gw ip: %v", err) } c.peerIP = gw } else { @@ -44,7 +47,7 @@ func NewController(config c.BgpConfig) (*Controller, error) { if config.LocalIP == "" { gw, err = via(c.peerIP) if err != nil { - return nil, fmt.Errorf("Unable to get gw ip: %v", err) + return nil, fmt.Errorf("unable to get gw ip: %v", err) } c.localIP, err = localAddress(gw) if err != nil { @@ -62,16 +65,23 @@ func NewController(config c.BgpConfig) (*Controller, error) { case "unknown": c.origin = 2 } + var rid string + if config.Family == 4 { + rid = c.localIP.String() + } + if config.RouterID != "" { + rid = config.RouterID + } s := gobgp.NewBgpServer() go s.Serve() if err := s.StartBgp(context.Background(), &api.StartBgpRequest{ Global: &api.Global{ As: uint32(config.LocalAS), - RouterId: c.localIP.String(), + RouterId: rid, ListenPort: -1, // gobgp won't listen on tcp:179 }, }); err != nil { - return nil, fmt.Errorf("Unable to start bgp: %v", err) + return nil, fmt.Errorf("unable to start bgp: %v", err) } c.s = s c.peerAS = config.PeerAS diff --git a/controller/system.go b/controller/system.go index 96146cc..6e6797c 100644 --- a/controller/system.go +++ b/controller/system.go @@ -18,8 +18,12 @@ func getCmdList(mainCmd string) []string { return cmdList } -func gateway() (net.IP, error) { - cmd := `ip route | grep "^default" | cut -d" " -f3` +func gateway(family int) (net.IP, error) { + prefix := "ip" + if family == 6 { + prefix = "ip -6" + } + cmd := fmt.Sprintf(`%s route | grep "^default" | cut -d" " -f3`, prefix) cmdList := getCmdList(cmd) out, err := exec.Command(execCmd, cmdList...).Output() if err != nil { @@ -29,7 +33,11 @@ func gateway() (net.IP, error) { } func via(dest net.IP) (net.IP, error) { - cmd := fmt.Sprintf(`ip route get %s | grep via | cut -d" " -f3`, dest.String()) + prefix := "ip" + if dest.To4() == nil { + prefix = "ip -6" + } + cmd := fmt.Sprintf(`%s route get %s | grep via | cut -d" " -f3`, prefix, dest.String()) cmdList := getCmdList(cmd) out, err := exec.Command(execCmd, cmdList...).Output() if err != nil { @@ -66,7 +74,11 @@ func addLoopback(name string, addr *net.IPNet) error { if len(label) > 15 { label = label[:15] } - cmd := fmt.Sprintf("ip address add %s/%d dev lo label %s", addr.IP.String(), prefixLen, label) + prefix := "ip" + if addr.IP.To4() == nil { + prefix = "ip -6" + } + cmd := fmt.Sprintf("%s address add %s/%d dev lo label %s", prefix, addr.IP.String(), prefixLen, label) cmdList := getCmdList(cmd) _, err := exec.Command(execCmd, cmdList...).Output() if err != nil { @@ -76,8 +88,12 @@ func addLoopback(name string, addr *net.IPNet) error { } func deleteLoopback(addr *net.IPNet) error { + prefix := "ip" + if addr.IP.To4() == nil { + prefix = "ip -6" + } prefixLen, _ := addr.Mask.Size() - cmd := fmt.Sprintf("ip address delete %s/%d dev lo", addr.IP.String(), prefixLen) + cmd := fmt.Sprintf("%s address delete %s/%d dev lo", prefix, addr.IP.String(), prefixLen) cmdList := getCmdList(cmd) _, err := exec.Command(execCmd, cmdList...).Output() if err != nil { @@ -87,9 +103,13 @@ func deleteLoopback(addr *net.IPNet) error { } func natRule(op string, vip, localAddr net.IP, protocol, lport, dport string) error { + prefix := "iptables" + if vip.To4() == nil { + prefix = "ip6tables" + } cmd := fmt.Sprintf( - "iptables -t nat -%s PREROUTING -p %s -d %s --dport %s -j DNAT --to-destination %s:%s", - op, protocol, vip.String(), lport, localAddr.String(), dport, + "%s -t nat -%s PREROUTING -p %s -d %s --dport %s -j DNAT --to-destination %s:%s", + prefix, op, protocol, vip.String(), lport, localAddr.String(), dport, ) cmdList := getCmdList(cmd) _, err := exec.Command(execCmd, cmdList...).Output()