Skip to content

Commit

Permalink
Add route info in output of "antctl get bgproutes" (#6803)
Browse files Browse the repository at this point in the history
Information includes the route type, along with a reference to
the corresponding K8s object when applicable.

Fixes #6794 

Signed-off-by: Kumar Atish <kumar.atish@broadcom.com>
  • Loading branch information
Atish-iaf authored Nov 26, 2024
1 parent 42bdb9f commit 814e05b
Show file tree
Hide file tree
Showing 8 changed files with 397 additions and 255 deletions.
26 changes: 15 additions & 11 deletions docs/antctl.md
Original file line number Diff line number Diff line change
Expand Up @@ -803,25 +803,29 @@ For more information about route advertisement, please refer to [Advertisements]
# Get the list of all advertised bgp routes
$ antctl get bgproutes

ROUTE
10.96.10.10/32
192.168.77.100/32
fec0::10:96:10:10/128
fec0::192:168:77:100/128
ROUTE TYPE K8S-OBJ-REF
172.18.0.3/32 EgressIP egress1
10.244.1.0/24 NodeIPAMPodCIDR <NONE>
10.96.0.1/32 ServiceLoadBalancerIP default/svc1
fec0::192:168:77:100/128 EgressIP egress2
fd00:10:244:1::/64 NodeIPAMPodCIDR <NONE>
fec0::10:96:10:10/128 ServiceLoadBalancerIP default/svc2

# Get the list of advertised IPv4 bgp routes
$ antctl get bgproutes --ipv4-only

ROUTE
10.96.10.10/32
192.168.77.100/32
ROUTE TYPE K8S-OBJ-REF
172.18.0.3/32 EgressIP egress1
10.244.1.0/24 NodeIPAMPodCIDR <NONE>
10.96.0.1/32 ServiceLoadBalancerIP default/svc1

# Get the list of advertised IPv6 bgp routes
$ antctl get bgproutes --ipv6-only

ROUTE
fec0::10:96:10:10/128
fec0::192:168:77:100/128
ROUTE TYPE K8S-OBJ-REF
fec0::192:168:77:100/128 EgressIP egress2
fd00:10:244:1::/64 NodeIPAMPodCIDR <NONE>
fec0::10:96:10:10/128 ServiceLoadBalancerIP default/svc2
```

### Upgrade existing objects of CRDs
Expand Down
8 changes: 5 additions & 3 deletions pkg/agent/apis/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,17 @@ func (r BGPPeerResponse) SortRows() bool {

// BGPRouteResponse describes the response struct of bgproutes command.
type BGPRouteResponse struct {
Route string `json:"route,omitempty"`
Route string `json:"route,omitempty"`
Type string `json:"type,omitempty"`
K8sObjRef string `json:"k8sObjRef,omitempty"`
}

func (r BGPRouteResponse) GetTableHeader() []string {
return []string{"ROUTE"}
return []string{"ROUTE", "TYPE", "K8S-OBJ-REF"}
}

func (r BGPRouteResponse) GetTableRow(_ int) []string {
return []string{r.Route}
return []string{r.Route, r.Type, r.K8sObjRef}
}

func (r BGPRouteResponse) SortRows() bool {
Expand Down
31 changes: 29 additions & 2 deletions pkg/agent/apiserver/handlers/bgproute/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import (
"encoding/json"
"errors"
"net/http"
"net/netip"
"reflect"
"slices"
"strings"

"k8s.io/klog/v2"

Expand Down Expand Up @@ -68,11 +71,35 @@ func HandleFunc(bq querier.AgentBGPPolicyInfoQuerier) http.HandlerFunc {
}

var bgpRoutesResp []apis.BGPRouteResponse
for _, bgpRoute := range bgpRoutes {
for bgpRoute := range bgpRoutes {
bgpRoutesResp = append(bgpRoutesResp, apis.BGPRouteResponse{
Route: bgpRoute,
Route: bgpRoute.Prefix,
Type: string(bgpRoutes[bgpRoute].Type),
K8sObjRef: bgpRoutes[bgpRoute].K8sObjRef,
})
}
// make sure that we provide a stable order for the API response
slices.SortFunc(bgpRoutesResp, func(a, b apis.BGPRouteResponse) int {
pA, _ := netip.ParsePrefix(a.Route)
pB, _ := netip.ParsePrefix(b.Route)
// IPv4 routes first, then IPv6 routes
if pA.Addr().Is4() && !pB.Addr().Is4() {
return -1
}
if !pA.Addr().Is4() && pB.Addr().Is4() {
return 1
}
// both routes are from the same IP family, now order based on route type
if n := strings.Compare(a.Type, b.Type); n != 0 {
return n
}
// finally, for routes of the same IP family and type, order based on prefix
// shorter prefixes come first; if the length is the same we order by IP
if n := pA.Bits() - pB.Bits(); n != 0 {
return n
}
return pA.Addr().Compare(pB.Addr())
})

if err := json.NewEncoder(w).Encode(bgpRoutesResp); err != nil {
w.WriteHeader(http.StatusInternalServerError)
Expand Down
89 changes: 77 additions & 12 deletions pkg/agent/apiserver/handlers/bgproute/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,42 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"k8s.io/utils/net"

"antrea.io/antrea/pkg/agent/apis"
"antrea.io/antrea/pkg/agent/controller/bgp"
"antrea.io/antrea/pkg/agent/bgp"
bgpcontroller "antrea.io/antrea/pkg/agent/controller/bgp"
queriertest "antrea.io/antrea/pkg/querier/testing"
)

const (
namespaceDefault = "default"
ipv4Suffix = "/32"
ipv6Suffix = "/128"
)

var (
podIPv4CIDR = "10.10.0.0/24"
podIPv4CIDRRoute = bgp.Route{Prefix: podIPv4CIDR}
clusterIPv4 = "10.96.10.10"
clusterIPv4Route = bgp.Route{Prefix: ipStrToPrefix(clusterIPv4)}
loadBalancerIPv6 = "fec0::192:168:77:150"
loadBalancerIPv6Route = bgp.Route{Prefix: ipStrToPrefix(loadBalancerIPv6)}
egressIPv6 = "fec0::192:168:77:200"
egressIPv6Route = bgp.Route{Prefix: ipStrToPrefix(egressIPv6)}

ipv4ClusterIPName = "clusterip-4"
ipv6LoadBalancerName = "loadbalancer-6"
ipv6EgressName = "egress-6"

allRoutes = map[bgp.Route]bgpcontroller.RouteMetadata{
clusterIPv4Route: {Type: bgpcontroller.ServiceClusterIP, K8sObjRef: getServiceName(ipv4ClusterIPName)},
loadBalancerIPv6Route: {Type: bgpcontroller.ServiceLoadBalancerIP, K8sObjRef: getServiceName(ipv6LoadBalancerName)},
egressIPv6Route: {Type: bgpcontroller.EgressIP, K8sObjRef: ipv6EgressName},
podIPv4CIDRRoute: {Type: bgpcontroller.NodeIPAMPodCIDR},
}
)

func TestBGPRouteQuery(t *testing.T) {
ctx := context.Background()
tests := []struct {
Expand All @@ -42,26 +72,35 @@ func TestBGPRouteQuery(t *testing.T) {
{
name: "bgpPolicyState does not exist",
expectedCalls: func(mockBGPServer *queriertest.MockAgentBGPPolicyInfoQuerier) {
mockBGPServer.EXPECT().GetBGPRoutes(context.Background(), true, true).Return(nil, bgp.ErrBGPPolicyNotFound)
mockBGPServer.EXPECT().GetBGPRoutes(context.Background(), true, true).Return(nil, bgpcontroller.ErrBGPPolicyNotFound)
},
expectedStatus: http.StatusNotFound,
},
{
name: "get all advertised routes",
expectedCalls: func(mockBGPServer *queriertest.MockAgentBGPPolicyInfoQuerier) {
mockBGPServer.EXPECT().GetBGPRoutes(ctx, true, true).Return(
[]string{"192.168.1.0/24", "192.168.2.0/24", "fec0::10:96:10:10/128"}, nil)
map[bgp.Route]bgpcontroller.RouteMetadata{
clusterIPv4Route: allRoutes[clusterIPv4Route],
podIPv4CIDRRoute: allRoutes[podIPv4CIDRRoute],
egressIPv6Route: allRoutes[egressIPv6Route],
}, nil)
},
expectedStatus: http.StatusOK,
expectedResponse: []apis.BGPRouteResponse{
{
Route: "192.168.1.0/24",
Route: podIPv4CIDR,
Type: string(bgpcontroller.NodeIPAMPodCIDR),
},
{
Route: "192.168.2.0/24",
Route: clusterIPv4Route.Prefix,
Type: string(allRoutes[clusterIPv4Route].Type),
K8sObjRef: allRoutes[clusterIPv4Route].K8sObjRef,
},
{
Route: "fec0::10:96:10:10/128",
Route: egressIPv6Route.Prefix,
Type: string(allRoutes[egressIPv6Route].Type),
K8sObjRef: allRoutes[egressIPv6Route].K8sObjRef,
},
},
},
Expand All @@ -70,15 +109,21 @@ func TestBGPRouteQuery(t *testing.T) {
url: "?ipv4-only",
expectedCalls: func(mockBGPServer *queriertest.MockAgentBGPPolicyInfoQuerier) {
mockBGPServer.EXPECT().GetBGPRoutes(ctx, true, false).Return(
[]string{"192.168.1.0/24", "192.168.2.0/24"}, nil)
map[bgp.Route]bgpcontroller.RouteMetadata{
clusterIPv4Route: allRoutes[clusterIPv4Route],
podIPv4CIDRRoute: allRoutes[podIPv4CIDRRoute],
}, nil)
},
expectedStatus: http.StatusOK,
expectedResponse: []apis.BGPRouteResponse{
{
Route: "192.168.1.0/24",
Route: podIPv4CIDRRoute.Prefix,
Type: string(allRoutes[podIPv4CIDRRoute].Type),
},
{
Route: "192.168.2.0/24",
Route: clusterIPv4Route.Prefix,
Type: string(allRoutes[clusterIPv4Route].Type),
K8sObjRef: allRoutes[clusterIPv4Route].K8sObjRef,
},
},
},
Expand All @@ -87,15 +132,22 @@ func TestBGPRouteQuery(t *testing.T) {
url: "?ipv6-only=",
expectedCalls: func(mockBGPServer *queriertest.MockAgentBGPPolicyInfoQuerier) {
mockBGPServer.EXPECT().GetBGPRoutes(ctx, false, true).Return(
[]string{"fec0::192:168:77:150/128", "fec0::10:10:0:10/128"}, nil)
map[bgp.Route]bgpcontroller.RouteMetadata{
loadBalancerIPv6Route: allRoutes[loadBalancerIPv6Route],
egressIPv6Route: allRoutes[egressIPv6Route],
}, nil)
},
expectedStatus: http.StatusOK,
expectedResponse: []apis.BGPRouteResponse{
{
Route: "fec0::192:168:77:150/128",
Route: egressIPv6Route.Prefix,
Type: string(allRoutes[egressIPv6Route].Type),
K8sObjRef: allRoutes[egressIPv6Route].K8sObjRef,
},
{
Route: "fec0::10:10:0:10/128",
Route: loadBalancerIPv6Route.Prefix,
Type: string(allRoutes[loadBalancerIPv6Route].Type),
K8sObjRef: allRoutes[loadBalancerIPv6Route].K8sObjRef,
},
},
},
Expand Down Expand Up @@ -136,3 +188,16 @@ func TestBGPRouteQuery(t *testing.T) {
})
}
}

func getServiceName(name string) string {
return namespaceDefault + "/" + name
}

func ipStrToPrefix(ipStr string) string {
if net.IsIPv4String(ipStr) {
return ipStr + ipv4Suffix
} else if net.IsIPv6String(ipStr) {
return ipStr + ipv6Suffix
}
return ""
}
Loading

0 comments on commit 814e05b

Please sign in to comment.