-
Notifications
You must be signed in to change notification settings - Fork 346
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
Implement the controller for API BGPPolicy #6203
base: main
Are you sure you want to change the base?
Conversation
e986dd8
to
16f2901
Compare
e93d476
to
7508c38
Compare
7508c38
to
e1e246a
Compare
f209e2a
to
3063737
Compare
57773d9
to
c9b727a
Compare
095d7da
to
5086b34
Compare
3bab09b
to
69c31a2
Compare
69c31a2
to
18c6f27
Compare
18c6f27
to
57bd548
Compare
Hi @hongliangl could you explain more about |
will add |
bgpPolicy: | ||
# The name of the Secret storing passwords of the BGP peers. For each BGP peer, the Secret key is generated by | ||
# concatenating its IP address and AS number, e.g., `192.168.1.1-65521`. | ||
secretName: {{ .Values.bgpPolicy.secretName | quote }} |
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.
Should we allow user to change this Secret name? I mean how would Antrea guarantee the ClusterRole being updated after this is changed?
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.
If users only modify the name but don't update the ClusterRole, we don't have a good solution to resolve that. The error logs may help users. What we can do is to document it well to remind users. I will refine the comment here to remind users about that.
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.
In other similar cases, we just hardcode the secret name and grant the secret's permission to agent, and no one has ever complained it. I think it could follow that, instead of making the secret name configurable.
} | ||
|
||
// Stop the stale BGP server if it exists. | ||
if bpState.bgpServer != nil { |
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 to stop stale BGP server after new BGP server? Won't be port conflict if other configs changes but not port?
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 question! I should stop the server first.
|
||
func (c *Controller) getRouterID() (string, error) { | ||
var routerID string | ||
// For IPv6 only environment, the BGP routerID should be specified by K8s Node annotation `antrea. io/ bgp-route-id`. |
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.
// For IPv6 only environment, the BGP routerID should be specified by K8s Node annotation `antrea. io/ bgp-route-id`. | |
// For IPv6 only environment, the BGP routerID should be specified by K8s Node annotation `antrea.io/bgp-route-id`. |
Question: if this is provided by users, how to avoid duplicate IDs?
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.
We cannot avoid duplicate IDs.
57bd548
to
11e6f39
Compare
This commit implements the controller of API `BGPPolicy`, designed to advertise Service IPs, Egress IPs, and Pod IPs to BGP peers from selected Nodes. According to the spec of `BGPPolicy`, the Node selector is used to select Nodes to which a `BGPPolicy` is applied. Multiple `BGPPolicies` can be applied to the same Node. However, only one `BGPPolicy` can be effective on a Node, with others serving as alternatives. The first `BGPPolicy` applied to a Node will be the effective one, and the latter ones will serve as alternatives. The effective one may be changed in the following cases: - The current effective BGPPolicy is updated and not applied to the Node. - The current effective BGPPolicy is deleted. - The antrea-agent is rebooted, and an original alternative BGPPolicy is synced first and becomes effective. The BGP server instance is only started for the effective BGPPolicy on a Node. If the effective BGPPolicy is changed, the corresponding BGP server instance will be terminated by calling the `Stop` method, and a new BGP server instance will be created and started by calling the `Start` method for the new effective BGPPolicy. To start a BGP server instance, ASN, routerID, and listen port must be specified. ASN and listen port are specified in the spec of the effective BGPPolicy. For routerID, if the cluster is IPv4 only or dual stack, the IPv4 NodeIP is used as the routerID; if the cluster is IPv6 only, the routerID must be specified in the Node annotation `antrea.io/bgp-route-id`. Additionally, a new BGP server instance should be created and started when any of ASN, routerID, or listen port changes. The information of the BGP peers is specified in the effective BGPPolicy. The unique identification of a BGP peer is the peer IP address. To reconcile the latest BGP peers: - Get the BGP peers to be added and add them by calling the `AddPeer` method of the BGP server instance. - Get the BGP peers to be deleted and delete them by calling the `RemovePeer` method of the BGP server instance. - Get the remaining BGP peers and calculate the updated BGP peers, then update them by calling the `UpdatePeer` method of the BGP server instance. The information of the IPs to be advertised can be calculated from the spec of the effective BGPPolicy. Currently, we advertise the IPs and CIDRs to all the BGP peers. To reconcile the latest IPs to all BGP peers: - If the BGP server instance is newly created and started, advertise all the IPs by calling the `AdvertiseRoutes` method. - If the BGP server instance is not newly created and started: - Get the IPs/CIDRs to be added and advertise them by calling the `AdvertiseRoutes` method. - Get the IPs/CIDRs to be removed and withdraw them by calling the `WithdrawRoutes` method. The feature is gated by the alpha `BGPPolicy` feature gate. Signed-off-by: Hongliang Liu <lhongliang@vmware.com>
11e6f39
to
2e762c8
Compare
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 haven't finished reviewing all code, but I feel the patch spends too many words and code for the unexpected case: multiple policies applied to a Node, making it like a normal case.
It's not a meaningful configuration and we should discourage users to do it, and there is no need to explain how we deal with such configurations in detail. "We could just have a note for users: If more than one BGPPolicy applies to a Node, only one will take effect."
bgpPolicy: | ||
# The name of the Secret storing passwords of the BGP peers. For each BGP peer, the Secret key is generated by | ||
# concatenating its IP address and AS number, e.g., `192.168.1.1-65521`. | ||
secretName: {{ .Values.bgpPolicy.secretName | quote }} |
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.
In other similar cases, we just hardcode the secret name and grant the secret's permission to agent, and no one has ever complained it. I think it could follow that, instead of making the secret name configurable.
@@ -0,0 +1,6 @@ | |||
apiVersion: v1 | |||
kind: Secret |
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 it needs to create the secret in advance?
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.
Do you mean that we should let users create the Secret? Is it a convention or something else?
@@ -31,7 +31,7 @@ edit the Agent configuration in the | |||
## List of Available Features | |||
|
|||
| Feature Name | Component | Default | Stage | Alpha Release | Beta Release | GA Release | Extra Requirements | Notes | | |||
| ----------------------------- | ------------------ | ------- | ----- | ------------- | ------------ | ---------- | ------------------ | --------------------------------------------- | | |||
|-------------------------------| ------------------ | ------- | ----- |---------------| ------------ | ---------- |--------------------| --------------------------------------------- | |
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'm not sure which is correct, having space or not having space. But this change makes them inconsistent.
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.
WIll rever this.
) | ||
|
||
const ( | ||
bgpRouteIDAnnotation = "antrea.io/bgp-route-id" |
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 will have comment to understand why we need annotation for IPv6 in another thread. But if this is really needed, please move it to pkg/agent/types/annotations.go and name it "bgp.antrea.io/router-id" (it should be router, not route, right?)
newBGPServerFn = func(globalConfig *bgp.GlobalConfig) bgp.Interface { | ||
return gobgp.NewGoBGPServer(globalConfig) | ||
} |
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.
newBGPServerFn = func(globalConfig *bgp.GlobalConfig) bgp.Interface { | |
return gobgp.NewGoBGPServer(globalConfig) | |
} | |
newBGPServerFn = gobgp.NewGoBGPServer |
And I think it's better to make it a member variable of Controller and assign gobgp.NewGoBGPServer
to it by default, then you don't need to revert it in tests.
// peers maps IP families to concatenated strings of BGP peer IP addresses and ASNs. | ||
// Example: "192.168.77.100-65000", "2001::1-65000". |
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 comment is wrong
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.
Will update.
peerKeys sets.Set[string] | ||
// peerConfigs maps concatenated string of BGP peer IP addresses and ASN to the configuration of the peer. | ||
peerConfigs map[string]bgp.PeerConfig |
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.
Aren't peerKeys redundant with peerConfigs' keys?
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.
peerKeys
can be removed. If so, we still need to collect all the keys of the current and the stale peerConfigs
to two sets, and then get the peers to be added or deleted.
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.
It can be easily got by sets.KeySet(peerConfigs)
, it's not a common "optimization" to use a separate set to store another map's keys, which may not be even more efficient as it still needs to maintain an extra set when writing.
for i := 0; i < defaultWorkers; i++ { | ||
go wait.Until(c.worker, time.Second, stopCh) | ||
} |
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 point to process multiple policies in parallel and have many code to handle the race condition.
In normal scenario, we expect only zero or single policy applied to the Node, we should just get one policy and implement it, instead of dealing with multiple policies like it's a normal case. If all jobs of implementing a single policy should be done sequentially, it just needs a single worker with a dummy key.
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 worker's implementation in my mind:
func syncBGPPolicy() error {
// Get 0 or 1 policy applied to the Node.
bgpPolicy, exists := c.getBGPPolicy()
if !exists {
// cleanup
}
// Implement the bgpPolicy
}
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 should we choose a BGPPolicy if users apply multiple ones to a Node anyway?
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.
Is it hard to get one item from a list of items?
This commit implements the controller of API
BGPPolicy
, designed to advertiseService IPs, Egress IPs, and Pod IPs to BGP peers from selected Nodes.
According to the spec of
BGPPolicy
, the Node selector is used to select Nodesto which a
BGPPolicy
is applied. MultipleBGPPolicies
can be applied to thesame Node. However, only one
BGPPolicy
can be effective on a Node, with othersserving as alternatives. The first
BGPPolicy
applied to a Node will be theeffective one, and the latter ones will serve as alternatives. The effective one
may be changed in the following cases:
first and becomes effective.
The BGP server instance is only started for the effective BGPPolicy on a Node.
Currently, the BGP server instance is implemented by goBGP, and more BGP
server implementations might be added later. If the effective BGPPolicy is changed,
the corresponding BGP server instance will be terminated by calling the
Stop()
method, and a new BGP server instance will be created and started by calling the
Start()
method for the new effective BGPPolicy.To start a BGP server instance, ASN, routerID, and listen port must be specified.
ASN and listen port are specified in the spec of the effective BGPPolicy. For
routerID, if the cluster is IPv4 only or dual stack, the IPv4 NodeIP is used as
the routerID; if the cluster is IPv6 only, the routerID must be specified in the
Node annotation
antrea.io/bgp-route-id
. Additionally, a new BGP server instanceshould be created and started when any of ASN, routerID, or listen port changes.
The information of the BGP peers is specified in the effective BGPPolicy. The
unique identification of a BGP peer is the peer IP address.
To reconcile the latest BGP peers:
AddPeers
method ofthe BGP server instance.
RemovePeers
method of the BGP server instance.
them by calling the
UpdatePeers
method of the BGP server instance.The information of the IPs to be advertised can be calculated from the spec of
the effective BGPPolicy. Currently, we advertise the IPs and CIDRs to all the
BGP peers.
To reconcile the latest IPs to all BGP peers:
by calling the
AdvertiseRoutes
method.AdvertiseRoutes
method.WithdrawRoutes
method.The feature is gated by the alpha
BGPPolicy
feature gate.Depends on #6009