[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.
|
| FamilyIPv4 uint8 = 4 | ||
| FamilyIPv6 uint8 = 6 | ||
|
|
||
| BridgedUplinkPrefix = "b-" |
There was a problem hiding this comment.
@wenyingd Which prefix you used in BM/VM?
There was a problem hiding this comment.
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.
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.
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.
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.
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.
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.
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.
Yes, but I think we can do this refactor in future.
| return i.ovsBridgeClient.SetInterfaceMTU(iface, mtu) | ||
| } | ||
|
|
||
| func getTransportIPNetDeviceByNameWithExcludedList(interfaceName string, excludedIPs []*net.IPNet) ([]*net.IPNet, error) { |
There was a problem hiding this comment.
Move this to path pkt/agent/util/net ? The same as function getTransportIPNetDeviceByName
There was a problem hiding this comment.
Rename as getTransportIPNetByNameWithExcludedList as it returns []*net.IPNet but not net interface?
There was a problem hiding this comment.
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.
| 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.
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.
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.
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.
OK. Let's keep existing changes.
6c32afe to
e5e432a
Compare
| return i.ovsBridgeClient.SetInterfaceMTU(iface, mtu) | ||
| } | ||
|
|
||
| func getTransportIPNetByNameWithExcludedList(interfaceName string, excludedIPs []*net.IPNet) ([]*net.IPNet, error) { |
There was a problem hiding this comment.
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.
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.
Removed unused parameter.
| 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.
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.
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.
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)
| return i.ovsBridgeClient.SetInterfaceMTU(iface, mtu) | ||
| } | ||
|
|
||
| func getTransportIPNetByNameWithExcludedList(interfaceName string, excludedIPs []*net.IPNet) ([]*net.IPNet, error) { |
There was a problem hiding this comment.
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.
| 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) |
| // 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.
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.
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.
Accepted Quan's comment. We can discuss here #3938 (comment) for reservedPorts cache.
| // 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.
This func should be moved OVSBridgeClient?
There was a problem hiding this comment.
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.
@wenyingd Any idea about this?
Current implementation is more flexible, and Jianjun's suggestion is safer.
| 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.
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?
| // 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.
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
| 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.
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.
Changed to GetAllIPNetsByName, since we already have GetIPNetDeviceByName
| // 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) { |
c79fc53 to
3f91116
Compare
| } | ||
|
|
||
| // 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 |
… port Add a suffix to uplink when bridging to OVS bridge. Signed-off-by: gran <gran@vmware.com>
|
/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