-
Notifications
You must be signed in to change notification settings - Fork 386
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
[flexible-ipam] Use uplink interface name for host interface internal port #3938
Conversation
Codecov Report
@@ Coverage Diff @@
## main #3938 +/- ##
==========================================
+ Coverage 64.58% 66.09% +1.51%
==========================================
Files 295 309 +14
Lines 43740 43875 +135
==========================================
+ Hits 28251 29001 +750
+ Misses 13215 12558 -657
- Partials 2274 2316 +42
*This pull request uses carry forward flags. Click here to find out more.
|
pkg/agent/util/net.go
Outdated
@@ -38,6 +38,8 @@ const ( | |||
|
|||
FamilyIPv4 uint8 = 4 | |||
FamilyIPv6 uint8 = 6 | |||
|
|||
BridgedUplinkPrefix = "b-" |
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.
@wenyingd Which prefix you used in BM/VM?
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.
Prefix phy
is used in VM support case. But I am thinking maybe ant
is better to represent it is renamed by Antrea, just like antctl? What's your thought @gran-vmv @mengdie-song ?
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 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.
Could we use antrea-
(as antrea-gw0, antrea-tun0), or you would choose a shorter prefix due to the interface length limit?
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 know NSX-T appends a single letter to the interface name (I remember it is ~
, like eth0~
).
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.
Linux has a property IFNAMSIZ
to limit the network interface name length to 15 bytes, thus I prefer to use short prefix/suffix, and I feel that suffix ~
is better. @wenyingd @tnqn @mengdie-song
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 am OK with the suffix, but I think we should test if it is working on Windows, let me try.
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 BM/VM and this PR, we'll restrict the uplink interface name length, thus we'd better choose a shorter prefix/suffix to improve the compatibility.
// Create uplink port. | ||
uplinkPortUUID, err := i.ovsBridgeClient.CreateUplinkPort(uplink, int32(i.nodeConfig.UplinkNetConfig.OFPort), map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUplink}) | ||
uplinkPortUUID, err := i.ovsBridgeClient.CreateUplinkPort(bridgedUplinkName, int32(uplinkNetConfig.OFPort), map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUplink}) |
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 possible to provide an API from ovsBridgeClient to support create a pair of ports? We could give the expected names of uplink and host internal port as parameters, along with other parameters like expected port MAC?
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.
Yes, but I think we can do this refactor in future.
pkg/agent/agent_linux.go
Outdated
@@ -312,3 +296,32 @@ func (i *Initializer) RestoreOVSBridge() { | |||
func (i *Initializer) setInterfaceMTU(iface string, mtu int) error { | |||
return i.ovsBridgeClient.SetInterfaceMTU(iface, mtu) | |||
} | |||
|
|||
func getTransportIPNetDeviceByNameWithExcludedList(interfaceName string, excludedIPs []*net.IPNet) ([]*net.IPNet, 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.
Move this to path pkt/agent/util/net ? The same as function getTransportIPNetDeviceByName
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.
Rename as getTransportIPNetByNameWithExcludedList
as it returns []*net.IPNet
but not net interface?
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.
Fixed name.
As you commented in getTransportIPNetDeviceByName
, we should keep this func in package agent, and do refactor in future if needed.
// getTransportIPNetDeviceByName is meant to be overridden for testing.
@@ -39,7 +39,7 @@ type OVSBridgeClient interface { | |||
SetInterfaceOptions(name string, options map[string]interface{}) Error | |||
CreatePort(name, ifDev string, externalIDs map[string]interface{}) (string, Error) | |||
CreateAccessPort(name, ifDev string, externalIDs map[string]interface{}, vlanID uint16) (string, Error) | |||
CreateInternalPort(name string, ofPortRequest int32, externalIDs map[string]interface{}) (string, 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.
I would prefer to add a new signature to support configuring port MAC with a specific value, since this is not a general case.
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 prefer to add MAC for this func, since MAC property is supported only in InternalPort, and the default value "" also matches OVS spec.
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 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 strong preference. Either way works for me. I feel no issue to add MAC to this 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.
No strong preference from me.
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.
OK. Let's keep existing changes.
6c32afe
to
e5e432a
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.
Overall LGTM, one ask.
pkg/agent/agent_linux.go
Outdated
@@ -312,3 +296,32 @@ func (i *Initializer) RestoreOVSBridge() { | |||
func (i *Initializer) setInterfaceMTU(iface string, mtu int) error { | |||
return i.ovsBridgeClient.SetInterfaceMTU(iface, mtu) | |||
} | |||
|
|||
func getTransportIPNetByNameWithExcludedList(interfaceName string, excludedIPs []*net.IPNet) ([]*net.IPNet, 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.
I didn't find a consumer of this function to provide valid excludedIPs
, is this parameter really needed?
I also mentioned the same question in VM patch, is it necessary in this function to filter only global IP address? I didn't find an example to say it is harm, but just a bit confuse on it.
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.
Agree with Wenying, generically we should avoid adding code/parameters that are not used anywhere to save development, review, maintenance efforts. They can be added any time when they are actually required.
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 unused parameter.
pkg/agent/agent_linux.go
Outdated
freePort, err := i.getFreeOFPort(config.UplinkOFPort) | ||
uplinkNetConfig.OFPort = uint32(freePort) | ||
klog.InfoS("Set OpenFlow port in UplinkNetConfig", "ofport", uplinkNetConfig.OFPort) | ||
freePort, err = i.getFreeOFPort(config.UplinkOFPort, []int32{freePort}) |
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 wonder if we should still use a predefined config.BridgeOFPort for the host interface to make the process of allocating ofport for well known ports consistent and less confusing to use config.UplinkOFPort
as start port for HostInterfaceOFPort
.
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.
Guess the problem is we may potentially have multiple uplinks. @wenyingd
But why we must allocate the port in advance, rather than let CreatePort() return a OFPort?
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.
config.UplinkOFPort
is a reserved port ID which is not valid in a port request.
This line means we apply for next available port ID and the start ID is UplinkOFPort.
Jianjun suggested another design in #3938 (comment)
pkg/agent/agent_linux.go
Outdated
@@ -312,3 +296,32 @@ func (i *Initializer) RestoreOVSBridge() { | |||
func (i *Initializer) setInterfaceMTU(iface string, mtu int) error { | |||
return i.ovsBridgeClient.SetInterfaceMTU(iface, mtu) | |||
} | |||
|
|||
func getTransportIPNetByNameWithExcludedList(interfaceName string, excludedIPs []*net.IPNet) ([]*net.IPNet, 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.
Agree with Wenying, generically we should avoid adding code/parameters that are not used anywhere to save development, review, maintenance efforts. They can be added any time when they are actually required.
@@ -39,7 +39,7 @@ type OVSBridgeClient interface { | |||
SetInterfaceOptions(name string, options map[string]interface{}) Error | |||
CreatePort(name, ifDev string, externalIDs map[string]interface{}) (string, Error) | |||
CreateAccessPort(name, ifDev string, externalIDs map[string]interface{}, vlanID uint16) (string, Error) | |||
CreateInternalPort(name string, ofPortRequest int32, externalIDs map[string]interface{}) (string, 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.
No strong preference from me.
pkg/agent/agent.go
Outdated
@@ -1144,8 +1144,11 @@ func (i *Initializer) getNodeInterfaceFromIP(nodeIPs *utilip.DualStackIPs) (v4IP | |||
// getFreeOFPort returns an OpenFlow port number which is not used by any existing OVS port. Note that, the returned port | |||
// is not saved in OVSDB yet before the real port is created, so it might introduce an issue for the same return value | |||
// if it is called multiple times before OVS port creation. | |||
func (i *Initializer) getFreeOFPort(startPort int) (int32, error) { | |||
func (i *Initializer) getFreeOFPort(startPort int, reservedPorts []int32) (int32, 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.
nit: getFreeOFPort(startPort int, reservedPorts ...int32)
also makes sense in this case and can avoid updating callers which don't need to set reservedPorts
.
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.
To make it simpler, should we maintain the allocated port numbers in OVSBridgeClient (so no need to have the callers pass the reservedPorts)?
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.
Accepted Quan's comment. We can discuss here #3938 (comment) for reservedPorts cache.
pkg/agent/agent.go
Outdated
@@ -1144,8 +1144,11 @@ func (i *Initializer) getNodeInterfaceFromIP(nodeIPs *utilip.DualStackIPs) (v4IP | |||
// getFreeOFPort returns an OpenFlow port number which is not used by any existing OVS port. Note that, the returned port | |||
// is not saved in OVSDB yet before the real port is created, so it might introduce an issue for the same return value | |||
// if it is called multiple times before OVS port creation. | |||
func (i *Initializer) getFreeOFPort(startPort int) (int32, error) { | |||
func (i *Initializer) getFreeOFPort(startPort int, reservedPorts []int32) (int32, 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.
This func should be moved OVSBridgeClient?
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.
To make it simpler, should we maintain the allocated port numbers in OVSBridgeClient (so no need to have the callers pass the reservedPorts)?
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.
@wenyingd Any idea about this?
Current implementation is more flexible, and Jianjun's suggestion is safer.
pkg/agent/agent_linux.go
Outdated
freePort, err := i.getFreeOFPort(config.UplinkOFPort) | ||
uplinkNetConfig.OFPort = uint32(freePort) | ||
klog.InfoS("Set OpenFlow port in UplinkNetConfig", "ofport", uplinkNetConfig.OFPort) | ||
freePort, err = i.getFreeOFPort(config.UplinkOFPort, []int32{freePort}) |
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.
Guess the problem is we may potentially have multiple uplinks. @wenyingd
But why we must allocate the port in advance, rather than let CreatePort() return a OFPort?
pkg/agent/agent.go
Outdated
@@ -1144,8 +1144,11 @@ func (i *Initializer) getNodeInterfaceFromIP(nodeIPs *utilip.DualStackIPs) (v4IP | |||
// getFreeOFPort returns an OpenFlow port number which is not used by any existing OVS port. Note that, the returned port | |||
// is not saved in OVSDB yet before the real port is created, so it might introduce an issue for the same return value | |||
// if it is called multiple times before OVS port creation. | |||
func (i *Initializer) getFreeOFPort(startPort int) (int32, error) { | |||
func (i *Initializer) getFreeOFPort(startPort int, reservedPorts []int32) (int32, 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.
To make it simpler, should we maintain the allocated port numbers in OVSBridgeClient (so no need to have the callers pass the reservedPorts)?
The workflow that allocating an OF port first then consuming it but not creating OVS port directlly is not about multiple uplink support, it is existing only in AntreaIPAM, because we need the expected uplink OF port number in the OpenFlow pipeline init stage to install many flows which is not per Pod perspective, but the uplink interface is attached to OVS after this stage, accurately, it should be performed when the flow-restored flag is set as true. For VM support or Windows cases, we don't have this additional requirement. |
The original question from Quan is whether we can use pre-defined constant OFPort for the host interface. And I guess one reason we do not do that is because we may support multiple uplinks later?
I did not remember the code well, but can we change the order to create the host port first? @wenyingd @gran-vmv |
We can use a pre-defined constant OFPort for the host interface, but this is not best practice since Wenying already added support for dynamic OFPort for HostInterface/Uplink port, and a constant may conflict with existing OFPort. (e.g. User created many regular Pods and then enable FlexibleIPAM) Previously we create BridgePort (br-int) as HostInterfacePort and it works well. However, since we need to change the BridgePort to an InternalPort with same name as Uplink, we can only create this port after Uplink is renamed.
|
I meant can we change to:
If we have to reserve OFPorts, I suggest to move the func into OVSBridgeClient, and maintain allocated OFPorts there, to simplify the caller side. |
We cannot change the sequence since antrea-agent is unable to access K8s apiserver after step 1, but this access is required by some other steps in initialization. |
896afe6
to
318dfa1
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.
two nits, otherwise LGTM
pkg/agent/util/net.go
Outdated
@@ -241,6 +243,25 @@ func GetIPNetDeviceByCIDRs(cidrsList []string) (v4IPNet, v6IPNet *net.IPNet, lin | |||
return nil, nil, nil, fmt.Errorf("unable to find local IP and device") | |||
} | |||
|
|||
func GetTransportIPNetByName(interfaceName string) ([]*net.IPNet, 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.
I think the qualifier “transport" shouldn't here. The function in pkg/agent/agent.go
has it because it's used to fetch transport interface's IPs, but this is a generic util function and its implementation has nothing to do with transport interface.
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.
Changed to GetAllIPNetsByName
, since we already have GetIPNetDeviceByName
pkg/ovs/ovsconfig/ovs_client.go
Outdated
// AllocateFreeOFPort returns an OpenFlow port number which is not allocated or used by any existing OVS port. Note | ||
// that, the returned port is cached locally but not saved in OVSDB yet before the real port is created, so it might | ||
// introduce an issue for the conflict if it is occupied by others before OVS port creation. | ||
func (br *OVSBridge) AllocateFreeOFPort(startPort int) (int32, 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.
Perhaps just AllocateOFPort
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.
Fixed.
c79fc53
to
3f91116
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.
A nit
pkg/ovs/ovsconfig/ovs_client.go
Outdated
@@ -796,6 +799,31 @@ func (br *OVSBridge) GetPortList() ([]OVSPortData, Error) { | |||
return portList, nil | |||
} | |||
|
|||
// AllocateOFPort returns an OpenFlow port number which is not allocated or used by any existing OVS port. Note that, | |||
// the returned port is cached locally but not saved in OVSDB yet before the real port is created, so it might introduce |
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.
port -> port number
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.
Fixed.
… port Add a suffix to uplink when bridging to OVS bridge. Signed-off-by: gran <gran@vmware.com>
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.
LGTM
/test-networkpolicy |
Use uplink interface name for host interface internal port, to support DHCP client.
Add a suffix to uplink when bridging to OVS bridge.
Signed-off-by: gran gran@vmware.com