Skip to content

Commit

Permalink
cnf network: add frrk8 metallb test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Gregory Kopels committed Sep 22, 2024
1 parent e4ddb12 commit 323da65
Show file tree
Hide file tree
Showing 4 changed files with 762 additions and 0 deletions.
188 changes: 188 additions & 0 deletions tests/cnf/core/network/metallb/internal/frr/frr.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,50 @@ type (
Bestpath bool `json:"bestpath,omitempty"`
} `json:"routes"`
}

advertisedRoute struct {
AddrPrefix string `json:"addrPrefix"`
PrefixLen int `json:"prefixLen"`
Network string `json:"network"`
NextHop string `json:"nextHop"`
Metric int `json:"metric"`
LocPrf int `json:"locPrf"`
Weight int `json:"weight"`
Path string `json:"path"`
BGPOriginCode string `json:"bgpOriginCode"`
}

BgpAdvertisedRoutes struct {

Check failure on line 61 in tests/cnf/core/network/metallb/internal/frr/frr.go

View workflow job for this annotation

GitHub Actions / build

exported: exported type BgpAdvertisedRoutes should have comment or be unexported (revive)
BGPTableVersion int `json:"bgpTableVersion"`
BGPLocalRouterId string `json:"bgpLocalRouterId"`

Check failure on line 63 in tests/cnf/core/network/metallb/internal/frr/frr.go

View workflow job for this annotation

GitHub Actions / build

var-naming: struct field BGPLocalRouterId should be BGPLocalRouterID (revive)
DefaultLocPrf int `json:"defaultLocPrf"`
LocalAS int `json:"localAS"`
AdvertisedRoutes map[string]advertisedRoute `json:"advertisedRoutes"`
}

BgpReceivedRoutes struct {

Check failure on line 69 in tests/cnf/core/network/metallb/internal/frr/frr.go

View workflow job for this annotation

GitHub Actions / build

exported: exported type BgpReceivedRoutes should have comment or be unexported (revive)
Routes map[string][]RouteInfo `json:"routes"`
}

RouteInfo struct {

Check failure on line 73 in tests/cnf/core/network/metallb/internal/frr/frr.go

View workflow job for this annotation

GitHub Actions / build

exported: exported type RouteInfo should have comment or be unexported (revive)
Prefix string `json:"prefix"`
PrefixLen int `json:"prefixLen"`
Protocol string `json:"protocol"`
Metric int `json:"metric"`
Uptime string `json:"uptime"`
Nexthops []Nexthop `json:"nexthops"`
}

Nexthop struct {

Check failure on line 82 in tests/cnf/core/network/metallb/internal/frr/frr.go

View workflow job for this annotation

GitHub Actions / build

exported: exported type Nexthop should have comment or be unexported (revive)
Flags int `json:"flags"`
Fib bool `json:"fib"`
IP string `json:"ip"`
Afi string `json:"afi"`
InterfaceIndex int `json:"interfaceIndex"`
InterfaceName string `json:"interfaceName"`
Active bool `json:"active"`
Weight int `json:"weight"`
}
)

// DefineBaseConfig defines minimal required FRR configuration.
Expand Down Expand Up @@ -91,6 +135,49 @@ func DefineBGPConfig(localBGPASN, remoteBGPASN int, neighborsIPAddresses []strin
return bgpConfig
}

// DefineBGPConfigWitgStaticRoutes returns string which represents BGP config file peering to all given IP addresses.
func DefineBGPConfigWitgStaticRoutes(localBGPASN, remoteBGPASN int, neighborsIPAddresses []string, multiHop, bfd bool) string {

bgpConfig := tsparams.FRRBaseConfig + fmt.Sprintf("ip route %s/32 172.16.0.10\n", neighborsIPAddresses[1]) +
fmt.Sprintf("ip route %s/32 172.16.0.11\n!\n", neighborsIPAddresses[0]) +
fmt.Sprintf("router bgp %d\n", localBGPASN) +
tsparams.FRRDefaultBGPPreConfig

for _, ipAddress := range neighborsIPAddresses {
bgpConfig += fmt.Sprintf(" neighbor %s remote-as %d\n neighbor %s password %s\n",
ipAddress, remoteBGPASN, ipAddress, tsparams.BGPPassword)

if bfd {
bgpConfig += fmt.Sprintf(" neighbor %s bfd\n", ipAddress)
}

if multiHop {
bgpConfig += fmt.Sprintf(" neighbor %s ebgp-multihop 2\n", ipAddress)
}
}

bgpConfig += "!\naddress-family ipv4 unicast\n"
for _, ipAddress := range neighborsIPAddresses {
bgpConfig += fmt.Sprintf(" neighbor %s activate\n", ipAddress)
}
bgpConfig += " network 192.168.100.0/24\n"
bgpConfig += " network 192.168.200.0/24\n"
bgpConfig += "exit-address-family\n"

// Add network commands only once for IPv6
bgpConfig += "!\naddress-family ipv6 unicast\n"
for _, ipAddress := range neighborsIPAddresses {
bgpConfig += fmt.Sprintf(" neighbor %s activate\n", ipAddress)
}
bgpConfig += " network 2001:100::0/64\n"
bgpConfig += " network 2001:200::0/64\n"
bgpConfig += "exit-address-family\n"

bgpConfig += "!\nline vty\n!\nend\n"

return bgpConfig
}

// BGPNeighborshipHasState verifies that BGP session on a pod has given state.
func BGPNeighborshipHasState(frrPod *pod.Builder, neighborIPAddress string, state string) (bool, error) {
var result map[string]bgpDescription
Expand Down Expand Up @@ -230,3 +317,104 @@ func runningConfig(frrPod *pod.Builder) (string, error) {

return bgpStateOut.String(), nil
}

func GetBGPAdvertisedRoutes(frrPod *pod.Builder, nodeIPs []string) (string, error) {

Check failure on line 321 in tests/cnf/core/network/metallb/internal/frr/frr.go

View workflow job for this annotation

GitHub Actions / build

exported: exported function GetBGPAdvertisedRoutes should have comment or be unexported (revive)
var allRoutes strings.Builder

// Loop through each nodeIP and execute the command
for _, nodeIP := range nodeIPs {
// Execute the BGP command for each nodeIP
routes, err := frrPod.ExecCommand(append(netparam.VtySh, fmt.Sprintf("sh ip bgp neighbors %s advertised-routes json", nodeIP)))
if err != nil {
return "", fmt.Errorf("error collecting BGP advertised routes from pod %s for nodeIP %s: %w",
frrPod.Definition.Name, nodeIP, err)
}

// Parse the BGP advertised routes for each nodeIP
bgpAdvertised, err := parseBGPAdvertisedRoutes(routes.String())
if err != nil {
return "", fmt.Errorf("error parsing BGP advertised routes for nodeIP %s: %w", nodeIP, err)
}

// Store the result for the current nodeIP
allRoutes.WriteString(fmt.Sprintf("Node IP: %s\n", nodeIP))
allRoutes.WriteString(bgpAdvertised)
allRoutes.WriteString("\n")
}

// Return all results combined
return allRoutes.String(), nil
}

func parseBGPAdvertisedRoutes(jsonData string) (string, error) {
var bgpRoutes BgpAdvertisedRoutes

// Parse the JSON data into the struct
err := json.Unmarshal([]byte(jsonData), &bgpRoutes)
if err != nil {
return "", fmt.Errorf("error parsing BGP advertised routes: %w", err)
}

// Format only the network values as a string
var result strings.Builder
for _, route := range bgpRoutes.AdvertisedRoutes {
result.WriteString(fmt.Sprintf("%s\n", route.Network))
}

return result.String(), nil
}

func VerifyBGPReceivedRoutes(frrk8sPods []*pod.Builder) (string, error) {

Check failure on line 367 in tests/cnf/core/network/metallb/internal/frr/frr.go

View workflow job for this annotation

GitHub Actions / build

exported: exported function VerifyBGPReceivedRoutes should have comment or be unexported (revive)
var result strings.Builder

for _, frrk8sPod := range frrk8sPods {
// Run the "sh ip route bgp json" command on each pod
output, err := frrk8sPod.ExecCommand(append(netparam.VtySh, "sh ip route bgp json"), "frr")
if err != nil {
return "", fmt.Errorf("error collecting BGP received routes from pod %s: %w",
frrk8sPod.Definition.Name, err)
}

// Parse the JSON output to get the BGP routes
bgpRoutes, err := parseBGPReceivedRoutes(output.String())

if err != nil {
return "", fmt.Errorf("error parsing BGP JSON from pod %s: %w", frrk8sPod.Definition.Name, err)
}

// Write the pod name to the result
result.WriteString(fmt.Sprintf("Pod: %s\n", frrk8sPod.Definition.Name))

// Extract and write the prefixes (keys of the Routes map) and corresponding route info
for prefix, routeInfos := range bgpRoutes.Routes {
result.WriteString(fmt.Sprintf(" Prefix: %s\n", prefix))
for _, routeInfo := range routeInfos {
result.WriteString(fmt.Sprintf(" Route Info: Prefix: %s", routeInfo.Prefix))
}
}

result.WriteString("\n") // Add an empty line between pods
}

return result.String(), nil
}

func parseBGPReceivedRoutes(jsonData string) (*BgpReceivedRoutes, error) {
var bgpRoutes map[string][]RouteInfo // This matches the structure of your JSON

// Parse the JSON data into the struct
err := json.Unmarshal([]byte(jsonData), &bgpRoutes)
if err != nil {
return nil, fmt.Errorf("error parsing BGP received routes: %w", err)
}

// Create a new BgpReceivedRoutes struct and populate it with the parsed data
parsedRoutes := &BgpReceivedRoutes{
Routes: bgpRoutes, // The map directly holds prefixes as keys
}

// Print the parsed routes for debugging
fmt.Printf("Parsed Routes: %+v\n", bgpRoutes)

return parsedRoutes, nil
}
2 changes: 2 additions & 0 deletions tests/cnf/core/network/metallb/internal/tsparams/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const (
LabelBGPTestCases = "bgp"
// LabelLayer2TestCases represents layer2 label that can be used for test cases selection.
LabelLayer2TestCases = "layer2"
// LabelFRRTestCases represents frrk8 label that can be used for test cases selection.
LabelFRRTestCases = "frrk8"
// BGPPassword var is used to set password for BGP session between FRR speakers.
BGPPassword = "bgp-test"
// DaemonsFile represents FRR default daemon configuration template.
Expand Down
3 changes: 3 additions & 0 deletions tests/cnf/core/network/metallb/internal/tsparams/mlbvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ var (
FRRK8sDefaultLabel = "component=frr-k8s"
// ExternalMacVlanNADName represents default external NetworkAttachmentDefinition name.
ExternalMacVlanNADName = "external"
// HubMacVlanNADName represents default external NetworkAttachmentDefinition name.
HubMacVlanNADName = "nad-hub"
// SleepCMD represents shel sleep command.
SleepCMD = []string{"/bin/bash", "-c", "sleep INF"}
// FRRContainerName represents default FRR's container name.
Expand Down Expand Up @@ -73,6 +75,7 @@ var (
"frrk8s_bgp_updates_total", "frrk8s_bgp_updates_total_received", "frrk8s_bgp_announced_prefixes_total",
"frrk8s_bgp_received_prefixes_total",
}
ExternalAdvertisedRoutes = []string{"192.168.100.0/24", "192.168.200.0/24"}

Check failure on line 78 in tests/cnf/core/network/metallb/internal/tsparams/mlbvars.go

View workflow job for this annotation

GitHub Actions / build

exported: exported var ExternalAdvertisedRoutes should have comment or be unexported (revive)
)

func setUnstructured(kind string) *unstructured.UnstructuredList {
Expand Down
Loading

0 comments on commit 323da65

Please sign in to comment.