-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support unnumbered BGP peering #212
Conversation
104a2fc
to
d1a45ba
Compare
ecdded6
to
4d465b0
Compare
@@ -117,7 +117,15 @@ type Neighbor struct { | |||
SourceAddress string `json:"sourceaddress,omitempty"` | |||
|
|||
// Address is the IP address to establish the session with. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can you add the // +optional
tag as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
internal/controller/api_to_config.go
Outdated
if n.Address == "" && n.Interface == "" { | ||
return nil, fmt.Errorf("neighbor %s has no Address or Interface specified", neighborName(n)) | ||
} | ||
|
||
if n.Address != "" && n.Interface != "" { | ||
return nil, fmt.Errorf("neighbor %s has both Address and Interface specified", neighborName(n)) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's put these first
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
internal/controller/api_to_config.go
Outdated
neighborFamily := ipfamily.Unknown | ||
if n.Address != "" && n.Interface == "" { | ||
neigh, err := ipfamily.ForAddresses(n.Address) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to find ipfamily for %s, %w", n.Address, err) | ||
} | ||
neighborFamily = neigh | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when this is below the validations, this can be if n.Address != ""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
internal/controller/api_to_config.go
Outdated
if n.Address == "" && n.Interface != "" { | ||
res.Unnumbered = true | ||
res.Addr = n.Interface | ||
res.IPFamily = ipfamily.DualStack | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's put this above the res, and change the if to n.Interface != ""
(or something like defaulting these with vars and only have the n.Address != ""
condition, overwriting them)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think done, but I am not sure I understood exactly what you suggested.
internal/controller/api_to_config.go
Outdated
return nil, fmt.Errorf("failed to find ipfamily for %s, %w", n.Address, err) | ||
neighborFamily := ipfamily.Unknown | ||
if n.Address != "" && n.Interface == "" { | ||
neigh, err := ipfamily.ForAddresses(n.Address) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: neigh
-> f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
ginkgo.DeferCleanup(func() { | ||
err := updater.CleanFRRConfiguration(cr) | ||
Expect(err).NotTo(HaveOccurred()) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: move this below the create
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
}) | ||
}) | ||
|
||
func validate(peer *frrcontainer.FRR, prefixes []string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same, more descriptive name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
Expect(err).NotTo(HaveOccurred()) | ||
for _, n := range neighbors { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should also verify that there are actual neighbors (len > 0 or something)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch, true, done
e2etests/tests/unnumbered.go
Outdated
Routers: []frrk8sv1beta1.Router{ | ||
{ | ||
ASN: infra.FRRK8sASN, | ||
Neighbors: []frrk8sv1beta1.Neighbor{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we also add a simple bfd here just to be sure it works?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good idea, not done, todo
@@ -68,6 +68,7 @@ type NeighborConfig struct { | |||
ASN string | |||
SrcAddr string | |||
Addr string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure I like that Addr
can now be both interface or address, but for now can you add a comment about it please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment added, but we can sure discuss what implementation you would like. Any suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback, all done except the addition of BFD
e2etests/tests/unnumbered.go
Outdated
// addresses in the interface. | ||
var _ = ginkgo.Describe("Unnumbered configure BGP peering", func() { | ||
var ( | ||
node corev1.Node |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
var ( | ||
node corev1.Node | ||
updater *config.Updater | ||
peer *frrcontainer.FRR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done (but if you have better name suggestion let me know)
e2etests/pkg/config/config.go
Outdated
@@ -80,3 +80,12 @@ func (u *Updater) Clean() error { | |||
|
|||
return nil | |||
} | |||
|
|||
func (u *Updater) CleanFRRConfiguration(cr frrk8sv1beta1.FRRConfiguration) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
updater, err = config.NewUpdater() | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
nodes, err := k8s.Nodes(k8sclient.New()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
Routers: []frrk8sv1beta1.Router{ | ||
{ | ||
ASN: infra.FRRK8sASN, | ||
Neighbors: []frrk8sv1beta1.Neighbor{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good idea, not done, todo
internal/controller/api_to_config.go
Outdated
if n.Address == "" && n.Interface == "" { | ||
return nil, fmt.Errorf("neighbor %s has no Address or Interface specified", neighborName(n)) | ||
} | ||
|
||
if n.Address != "" && n.Interface != "" { | ||
return nil, fmt.Errorf("neighbor %s has both Address and Interface specified", neighborName(n)) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
internal/controller/api_to_config.go
Outdated
neighborFamily := ipfamily.Unknown | ||
if n.Address != "" && n.Interface == "" { | ||
neigh, err := ipfamily.ForAddresses(n.Address) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to find ipfamily for %s, %w", n.Address, err) | ||
} | ||
neighborFamily = neigh | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
internal/controller/api_to_config.go
Outdated
if n.Address == "" && n.Interface != "" { | ||
res.Unnumbered = true | ||
res.Addr = n.Interface | ||
res.IPFamily = ipfamily.DualStack | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think done, but I am not sure I understood exactly what you suggested.
err: nil, | ||
}, | ||
{ | ||
name: "Neighbor with without Interface and without Address", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -68,6 +68,7 @@ type NeighborConfig struct { | |||
ASN string | |||
SrcAddr string | |||
Addr string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment added, but we can sure discuss what implementation you would like. Any suggestions?
Added one commit that I will squash, now I am testing with BFD the session. |
500f5f7
to
de8afe2
Compare
e2etests/tests/unnumbered.go
Outdated
|
||
externalP2PContainer, err := frrcontainer.CreateP2PPeerFor(nodeWithP2PConnection.Name, iface, FRRImage) | ||
Expect(err).NotTo(HaveOccurred()) | ||
ginkgo.By(fmt.Sprintf("create p2p %s:%s -- %s:%s)", nodeWithP2PConnection.Name, iface, iface, externalP2PContainer.Name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create -> creating + move this above the CreateP2P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done ( need to skip the real name though)
e2etests/tests/unnumbered.go
Outdated
Expect(err).NotTo(HaveOccurred()) | ||
}) | ||
|
||
ginkgo.By(fmt.Sprintf("load frrconfig to %s", externalP2PContainer.Name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: -> updating frr config for container %s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
err = externalP2PContainer.UpdateBGPConfigFile(c) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
ginkgo.By(fmt.Sprintf("apply frrconfiguration %s", "for-"+externalP2PContainer.Name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> peering node %s with its p2p container %s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
ginkgo.DescribeTable("BGP session is established and routes are verified", func(rc frrconfig.RouterConfigUnnumbered) { | ||
iface := rc.Interface | ||
remoteASN := rc.ASNLocal | ||
prefixSend := []string{"5.5.5.0/24", "5555::/64"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put this closer to where it's needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added on top, I think it fits better
e2etests/tests/unnumbered.go
Outdated
Expect(err).NotTo(HaveOccurred()) | ||
peerLLA, err := container.GetIPv6Link(externalP2PContainer.Name, iface) | ||
Expect(err).NotTo(HaveOccurred()) | ||
ginkgo.By(fmt.Sprintf("%s/%s/%s --- %s/%s/%s", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By("validating the node and p2p container peered")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
// We can also use existing functions if fix the frr.Ipv4 to be LLA | ||
pod, err := k8s.FRRK8sPodOnNode(cs, nodeWithP2PConnection.Name) | ||
Expect(err).NotTo(HaveOccurred()) | ||
ValidateNodesHaveRoutes([]*corev1.Pod{pod}, *externalP2PContainer, rc.ToAdvertiseV4, rc.ToAdvertiseV6) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does this add?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nothing I let it there to let you know that the usual function can work also in case you wanted to use that. Removed
e2etests/tests/unnumbered.go
Outdated
}) | ||
}) | ||
|
||
func validateBGPPeering(peer *frrcontainer.FRR, lla string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: validateBGPPeering -> validateUnnumberedBGPPeering ? also lla -> nodeLLA ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
return nil | ||
} | ||
} | ||
return fmt.Errorf("no connected neighbor was found") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
modify this to include the node's lla
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
} | ||
|
||
func validatePrefixViaFor(peer executor.Executor, dev, nextHop string, prefixes ...string) { | ||
ginkgo.By(fmt.Sprintf("validate prefix %s via %s dev %s", prefixes, nextHop, dev)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
validate -> validating
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
}) | ||
|
||
func validateBGPPeering(peer *frrcontainer.FRR, lla string) { | ||
ginkgo.By(fmt.Sprintf("validate BGP peering to %s", peer.Name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
validate -> validating, from %s to %s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hope I did not miss something, thanks for the feedback @oribon
e2etests/tests/unnumbered.go
Outdated
// we cannot use | ||
// ValidatePrefixesForNeighbor(*externalP2PContainer, []corev1.Node{nodeWithP2PConnection}, prefixSend...) | ||
// because deep down the LLA ip cannot be found as part of the node |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think done
e2etests/tests/unnumbered.go
Outdated
// We can also use existing functions if fix the frr.Ipv4 to be LLA | ||
pod, err := k8s.FRRK8sPodOnNode(cs, nodeWithP2PConnection.Name) | ||
Expect(err).NotTo(HaveOccurred()) | ||
ValidateNodesHaveRoutes([]*corev1.Pod{pod}, *externalP2PContainer, rc.ToAdvertiseV4, rc.ToAdvertiseV6) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nothing I let it there to let you know that the usual function can work also in case you wanted to use that. Removed
e2etests/tests/unnumbered.go
Outdated
} | ||
|
||
func validatePrefixViaFor(peer executor.Executor, dev, nextHop string, prefixes ...string) { | ||
ginkgo.By(fmt.Sprintf("validate prefix %s via %s dev %s", prefixes, nextHop, dev)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
ginkgo.DescribeTable("BGP session is established and routes are verified", func(rc frrconfig.RouterConfigUnnumbered) { | ||
iface := rc.Interface | ||
remoteASN := rc.ASNLocal | ||
prefixSend := []string{"5.5.5.0/24", "5555::/64"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added on top, I think it fits better
e2etests/tests/unnumbered.go
Outdated
Expect(err).NotTo(HaveOccurred()) | ||
}) | ||
|
||
ginkgo.By(fmt.Sprintf("load frrconfig to %s", externalP2PContainer.Name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
|
||
validateBGPPeering(externalP2PContainer, nodeLLA) | ||
|
||
ginkgo.By(fmt.Sprintf("validate routing table on %s (prefixSend)", externalP2PContainer.Name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
// ValidatePrefixesForNeighbor(*externalP2PContainer, []corev1.Node{nodeWithP2PConnection}, prefixSend...) | ||
// because deep down the LLA ip cannot be found as part of the node | ||
|
||
ginkgo.By(fmt.Sprintf("validate routing table on %s (prefixReceive)", nodeWithP2PConnection.Name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
}) | ||
}) | ||
|
||
func validateBGPPeering(peer *frrcontainer.FRR, lla string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
}) | ||
|
||
func validateBGPPeering(peer *frrcontainer.FRR, lla string) { | ||
ginkgo.By(fmt.Sprintf("validate BGP peering to %s", peer.Name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
return nil | ||
} | ||
} | ||
return fmt.Errorf("no connected neighbor was found") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
c6d870b
to
62264b7
Compare
internal/controller/api_to_config.go
Outdated
if err != nil { | ||
return nil, fmt.Errorf("failed to find ipfamily for %s, %w", n.Address, err) | ||
if n.Address == "" && n.Interface == "" { | ||
return nil, fmt.Errorf("there is a neighbor with no interface and address") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: let's say which neighbor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how? both interface and address is empty, which field should I print ASN?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, that for example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do that . Fyi @oribon if I remember that error message was your feedback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
internal/frr/parse_test.go
Outdated
@@ -530,6 +531,215 @@ func TestNeighbours(t *testing.T) { | |||
} | |||
} | |||
|
|||
const unnumberedNeihbours = ` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo in neighbors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
res := &frr.NeighborConfig{ | ||
Name: neighborName(n), | ||
ASN: asnFor(n), | ||
SrcAddr: n.SourceAddress, | ||
Addr: n.Address, | ||
Addr: address, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the fact that we hide the interface under Addr here. Can we have an explicit field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that name Addr and the value looks not ideal.
Given that FRR itself is using the word PEER to indicate either Addr or Interface name neighbor PEER interface remote-as <internal|external|auto|ASN
What do you think about renaming .Addr to .Peer? Or you prefer to have .Interface field?
I am not in favor of two field because it means everytime we are using .Addr (e.g. error) we should add logic if .Addr empty use the .Interface (but is not that we currently reference that a lot, is more about the future, so not strong argument)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would've agreed if we hadn't to make logic on the fact that it is unnumbered or not, but we are doing it:
neighbor {{.neighbor.Addr}}{{ if .neighbor.Unnumbered }} interface{{ end }} remote-as {{.neighbor.ASN}}
if that's the case I'd prefer having a clear api where fields named explicitly and if we need to call out errors, have a function that returns the proper string (as we do elsewhere).
Names and fields are (almost) free, and we should strive for clarity first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not done, TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
) | ||
|
||
ginkgo.BeforeEach(func() { | ||
if _, found := os.LookupEnv("RUN_FRR_CONTAINER_ON_HOST_NETWORK"); found { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's leave this to the caller. I'd rather have the runner willingly opt out instead of having discovery logic in the tests themselves
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure I can remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e2etests/tests/unnumbered.go
Outdated
err = updater.Update([]corev1.Secret{}, cr) | ||
Expect(err).NotTo(HaveOccurred()) | ||
ginkgo.DeferCleanup(func() { | ||
err := updater.DeleteFRRConfiguration(cr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need this and the clean we are doing in beforeEach is not enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the clean in beforeEach is generic clean all so is enough and currently required because most tests do not cleanup their CRs. Nevertheless from gikngko perspective it is recommended each test to cleanup the resources, for example if we want to move towards parallel test that is a small contribution.
Given you comment I will remove it also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's bugging me is that all the tests clean the configuration to start with a clean slate, then I land on this and have to spend extra energy to understand why it's different, just to find out that it's unnecessary.
So yes, let's keep the structure consistent with the other tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed for consistency
(but for the record is bugging me the opposite, why tests are not take care of the cleanup)
e2etests/tests/unnumbered.go
Outdated
) | ||
|
||
// This spec is added to verify that the point-to-point setup works | ||
ginkgo.When("raw config", func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mind explaining why using When instead of "context" as per all the other tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No real reason, I suppose to avoid having the "when" in the description. Not sure if there is any guidance when When should be used instead of Context.
I will correct it so test looks similar
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no guidance, and I even did not know about when
. I'd rather keep consistency if there is no real need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done (test was removed)
e2etests/tests/unnumbered.go
Outdated
}), | ||
) | ||
|
||
// This spec is added to verify that the point-to-point setup works |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understood. What's the difference with the other test (apart from using the raw config?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is actually checking that the create container, the p2p wire function , and the unnumber peer config works, without depending on actual code.
E.g. if that test is failing we should be looking whether test code change, external peer config, docker version, frr version introduced something.
Do you prefer that I remove it or update the comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remove it. I understand what you mean, but the point of having a CI is to run it incrementally every change and have vision of what's breaking and when. So ideally, if changing a test or frr or docker version is breaking, we'll find out when we apply that change.
Under this logic we should duplicate all our tests to use raw config too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Under this logic we should duplicate all our tests to use raw config too.
No other test is setting up neighbor in a unique way so I do not agree fully with that but no strong opinion to keep it also.
res := &frr.NeighborConfig{ | ||
Name: neighborName(n), | ||
ASN: asnFor(n), | ||
SrcAddr: n.SourceAddress, | ||
Addr: n.Address, | ||
Addr: address, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would've agreed if we hadn't to make logic on the fact that it is unnumbered or not, but we are doing it:
neighbor {{.neighbor.Addr}}{{ if .neighbor.Unnumbered }} interface{{ end }} remote-as {{.neighbor.ASN}}
if that's the case I'd prefer having a clear api where fields named explicitly and if we need to call out errors, have a function that returns the proper string (as we do elsewhere).
Names and fields are (almost) free, and we should strive for clarity first.
The API changes ``` type Neighbor struct { Address string `json:address` Interface string `json:interface` } ``` For metrics when we have unnumbered peering the `vtysh show neigh` return a key that is not a valid IP (is `net0`), code was modified accordingly ``` frrk8s_bgp_announced_prefixes_total{peer="net1",vrf="default"} 0 frrk8s_bgp_keepalives_received{peer="net1",vrf="default"} 0 frrk8s_bgp_keepalives_sent{peer="net1",vrf="default"} 0 frrk8s_bgp_notifications_sent{peer="net1",vrf="default"} 0 frrk8s_bgp_opens_received{peer="net1",vrf="default"} 0 ``` Signed-off-by: karampok <karampok@gmail.com>
With the new version we need to change the .IP of the neighbor to .ID. The struct in metallb/e2etest looks as follows: ``` type Neighbor struct { // ID is the key that vtysh returns for the neighbor, // it can be either IP or interface name if unnumbered. ID string VRF string ``` Signed-off-by: karampok <karampok@gmail.com>
The test requires point-to-point connection so we cannot use any existing infra peer. Therefore a new peer (docker container) runs with no network, and point-to-point connections are created using `sudo ip` commands. There are three specs ``` Unnumbered BGP session is established and routes are verified iBGP Unnumbered BGP session is established and routes are verified eBGP ``` Signed-off-by: karampok <karampok@gmail.com>
LGTM, sending to merge queue |
/kind feature
What this PR does / why we need it:
As the result of this design proposal
https://github.com/metallb/metallb/blob/main/design/unnumbered-bgp.md
Special notes for your reviewer:
Currently depends on this PR that adds the test functions needed
metallb/metallb#2595,
Release note: