Skip to content

Commit 0f86e78

Browse files
author
Murali Reddy
committed
Adds support for advertising cluster IP correponding to a service to the BGP peers
Once external BGP is peered with cluster nodes, pods can be routable externally fixes #4 and #7
1 parent bcb4c50 commit 0f86e78

File tree

3 files changed

+102
-9
lines changed

3 files changed

+102
-9
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ Alternatively you can download the prebuilt binary from https://github.com/cloud
4343
--kubeconfig string Path to kubeconfig file with authorization information (the master location is set by the master flag).
4444
--master string The address of the Kubernetes API server (overrides any value in kubeconfig)
4545
--routes-sync-period duration The maximum interval of how often routes are advertised and learned (e.g. '5s', '1m', '2h22m'). Must be greater than 0. (default 1m0s)
46+
--advertise-cluster-ip If true then cluster IP will be added into the RIB and will be advertised to the peers. False by default.
47+
--cluster-asn ASN number under which cluster nodes will run iBGP
48+
--peer-asn ASN number of the BGP peer to which cluster nodes will advertise cluster ip and node's pod cidr
49+
--peer-router The ip address of the external router to which all nodes will peer and advertise the cluster ip and pod cidr's
4650
```
4751

4852
### deployment

app/controllers/network_routes_controller.go

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"time"
1111

1212
"github.com/cloudnativelabs/kube-router/app/options"
13+
"github.com/cloudnativelabs/kube-router/app/watchers"
1314
"github.com/cloudnativelabs/kube-router/utils"
1415
"github.com/golang/glog"
1516
bgpapi "github.com/osrg/gobgp/api"
@@ -23,12 +24,16 @@ import (
2324
)
2425

2526
type NetworkRoutingController struct {
26-
nodeIP net.IP
27-
nodeHostName string
28-
mu sync.Mutex
29-
clientset *kubernetes.Clientset
30-
bgpServer *gobgp.BgpServer
31-
syncPeriod time.Duration
27+
nodeIP net.IP
28+
nodeHostName string
29+
mu sync.Mutex
30+
clientset *kubernetes.Clientset
31+
bgpServer *gobgp.BgpServer
32+
syncPeriod time.Duration
33+
advertiseClusterIp bool
34+
peerRouter string
35+
asnNumber uint32
36+
peerAsnNumber uint32
3237
}
3338

3439
func (nrc *NetworkRoutingController) Run(stopCh <-chan struct{}, wg *sync.WaitGroup) {
@@ -70,17 +75,31 @@ func (nrc *NetworkRoutingController) Run(stopCh <-chan struct{}, wg *sync.WaitGr
7075
if nodeIP.String() == nrc.nodeIP.String() {
7176
continue
7277
}
78+
7379
n := &config.Neighbor{
7480
Config: config.NeighborConfig{
7581
NeighborAddress: nodeIP.String(),
76-
PeerAs: 65000,
82+
PeerAs: nrc.asnNumber,
7783
},
7884
}
7985
if err := nrc.bgpServer.AddNeighbor(n); err != nil {
8086
panic(err)
8187
}
8288
}
8389

90+
// if the global routing peer is configured then peer with it
91+
if len(nrc.peerRouter) != 0 {
92+
n := &config.Neighbor{
93+
Config: config.NeighborConfig{
94+
NeighborAddress: nrc.peerRouter,
95+
PeerAs: nrc.peerAsnNumber,
96+
},
97+
}
98+
if err := nrc.bgpServer.AddNeighbor(n); err != nil {
99+
glog.Errorf("Failed to peer with global peer routeri: %s", nrc.peerRouter)
100+
}
101+
}
102+
84103
// loop forever till notified to stop on stopCh
85104
for {
86105
select {
@@ -90,6 +109,17 @@ func (nrc *NetworkRoutingController) Run(stopCh <-chan struct{}, wg *sync.WaitGr
90109
default:
91110
}
92111

112+
// advertise cluster IP for the service to be reachable via host
113+
if nrc.advertiseClusterIp {
114+
glog.Infof("Advertising cluster ips")
115+
for _, svc := range watchers.ServiceWatcher.List() {
116+
if svc.Spec.Type == "ClusterIP" || svc.Spec.Type == "NodePort" {
117+
glog.Infof("found a service of cluster ip type")
118+
nrc.AdvertiseClusterIp(svc.Spec.ClusterIP)
119+
}
120+
}
121+
}
122+
93123
glog.Infof("Performing periodic syn of the routes")
94124
err := nrc.advertiseRoute()
95125
if err != nil {
@@ -149,6 +179,21 @@ func (nrc *NetworkRoutingController) advertiseRoute() error {
149179
return nil
150180
}
151181

182+
func (nrc *NetworkRoutingController) AdvertiseClusterIp(clusterIp string) error {
183+
184+
attrs := []bgp.PathAttributeInterface{
185+
bgp.NewPathAttributeOrigin(0),
186+
bgp.NewPathAttributeNextHop(nrc.nodeIP.String()),
187+
bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{4000, 400000, 300000, 40001})}),
188+
}
189+
glog.Infof("Advertising route: '%s/%s via %s' to peers", clusterIp, strconv.Itoa(32), nrc.nodeIP.String())
190+
if _, err := nrc.bgpServer.AddPath("", []*table.Path{table.NewPath(nil, bgp.NewIPAddrPrefix(uint8(32),
191+
clusterIp), false, attrs, time.Now(), false)}); err != nil {
192+
return fmt.Errorf(err.Error())
193+
}
194+
return nil
195+
}
196+
152197
func (nrc *NetworkRoutingController) injectRoute(path *table.Path) error {
153198
nexthop := path.GetNexthop()
154199
nlri := path.GetNlri()
@@ -174,6 +219,41 @@ func NewNetworkRoutingController(clientset *kubernetes.Clientset, kubeRouterConf
174219
nrc.syncPeriod = kubeRouterConfig.RoutesSyncPeriod
175220
nrc.clientset = clientset
176221

222+
if len(kubeRouterConfig.ClusterAsn) != 0 {
223+
asn, err := strconv.ParseUint(kubeRouterConfig.ClusterAsn, 0, 32)
224+
if err != nil {
225+
panic("Invalid cluster ASN: " + err.Error())
226+
}
227+
if asn > 65534 || asn < 64512 {
228+
panic("Invalid ASN number for cluster ASN")
229+
}
230+
nrc.asnNumber = uint32(asn)
231+
} else {
232+
nrc.asnNumber = 64512 // this magic number is first of the private ASN range, use it as default
233+
}
234+
235+
nrc.advertiseClusterIp = kubeRouterConfig.AdvertiseClusterIp
236+
237+
if len(kubeRouterConfig.PeerRouter) != 0 {
238+
if net.ParseIP(kubeRouterConfig.PeerRouter) == nil {
239+
panic("Invalid peer router ip: " + nrc.peerRouter)
240+
}
241+
242+
nrc.peerRouter = kubeRouterConfig.PeerRouter
243+
244+
if len(kubeRouterConfig.PeerAsn) == 0 {
245+
panic("ASN number for peer router must be specified")
246+
}
247+
asn, err := strconv.ParseUint(kubeRouterConfig.PeerAsn, 0, 32)
248+
if err != nil {
249+
panic("Invalid BGP peer ASN: " + err.Error())
250+
}
251+
if asn > 65534 {
252+
panic("Invalid ASN number for cluster ASN")
253+
}
254+
nrc.peerAsnNumber = uint32(asn)
255+
}
256+
177257
nodeHostName, err := os.Hostname()
178258
if err != nil {
179259
panic(err.Error())
@@ -198,7 +278,7 @@ func NewNetworkRoutingController(clientset *kubernetes.Clientset, kubeRouterConf
198278

199279
global := &config.Global{
200280
Config: config.GlobalConfig{
201-
As: 65000,
281+
As: nrc.asnNumber,
202282
RouterId: nrc.nodeIP.String(),
203283
},
204284
}

app/options/options.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ type KubeRouterConfig struct {
1818
RunFirewall bool
1919
RunRouter bool
2020
MasqueradeAll bool
21+
AdvertiseClusterIp bool
22+
PeerRouter string
23+
ClusterAsn string
24+
PeerAsn string
2125
}
2226

2327
func NewKubeRouterConfig() *KubeRouterConfig {
@@ -28,7 +32,8 @@ func NewKubeRouterConfig() *KubeRouterConfig {
2832
MasqueradeAll: false,
2933
RunServiceProxy: true,
3034
RunFirewall: true,
31-
RunRouter: true}
35+
RunRouter: true,
36+
AdvertiseClusterIp: false}
3237
}
3338

3439
func (s *KubeRouterConfig) AddFlags(fs *pflag.FlagSet) {
@@ -43,4 +48,8 @@ func (s *KubeRouterConfig) AddFlags(fs *pflag.FlagSet) {
4348
fs.DurationVar(&s.IPTablesSyncPeriod, "iptables-sync-period", s.IPTablesSyncPeriod, "The maximum interval of how often iptables rules are refreshed (e.g. '5s', '1m'). Must be greater than 0.")
4449
fs.DurationVar(&s.IpvsSyncPeriod, "ipvs-sync-period", s.IpvsSyncPeriod, "The maximum interval of how often ipvs config is refreshed (e.g. '5s', '1m', '2h22m'). Must be greater than 0.")
4550
fs.DurationVar(&s.RoutesSyncPeriod, "routes-sync-period", s.RoutesSyncPeriod, "The maximum interval of how often routes are adrvertised and learned (e.g. '5s', '1m', '2h22m'). Must be greater than 0.")
51+
fs.BoolVar(&s.AdvertiseClusterIp, "advertise-cluster-ip", s.AdvertiseClusterIp, "If true then cluster IP will be added into the RIB and will be advertised to the peers. False by default.")
52+
fs.StringVar(&s.PeerRouter, "peer-router", s.PeerRouter, "The ip address of the external router to which all nodes will peer and advertise the cluster ip and pod cidr's")
53+
fs.StringVar(&s.ClusterAsn, "cluster-asn", s.ClusterAsn, "ASN number under which cluster nodes will run iBGP")
54+
fs.StringVar(&s.PeerAsn, "peer-asn", s.PeerAsn, "ASN number of the BGP peer to which cluster nodes will advertise cluster ip and node's pod cidr")
4655
}

0 commit comments

Comments
 (0)