libnetwork/osl: make constructing Interfaces more atomic

It's still not "great", but implement a `newInterface()` constructor
to create a new Interface instance, instead of creating a partial
instance and applying "options" after the fact.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2023-08-21 12:24:46 +02:00
parent 47f9e70385
commit 9d3b1f9419
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
3 changed files with 29 additions and 38 deletions

View file

@ -14,6 +14,31 @@ import (
"github.com/vishvananda/netns"
)
// newInterface creates a new interface in the given namespace using the
// provided options.
func newInterface(ns *Namespace, srcName, dstPrefix string, options ...IfaceOption) (*Interface, error) {
i := &Interface{
srcName: srcName,
dstName: dstPrefix,
ns: ns,
}
for _, opt := range options {
if opt != nil {
// TODO(thaJeztah): use multi-error instead of returning early.
if err := opt(i); err != nil {
return nil, err
}
}
}
if i.master != "" {
i.dstMaster = ns.findDst(i.master, true)
if i.dstMaster == "" {
return nil, fmt.Errorf("could not find an appropriate master %q for %q", i.master, i.srcName)
}
}
return i, nil
}
// Interface represents the settings and identity of a network device.
// It is used as a return type for Network.Link, and it is common practice
// for the caller to use this information when moving interface SrcName from
@ -135,23 +160,11 @@ func (n *Namespace) findDst(srcName string, isBridge bool) string {
// to only provide a prefix for DstName. The AddInterface api will auto-generate
// an appropriate suffix for the DstName to disambiguate.
func (n *Namespace) AddInterface(srcName, dstPrefix string, options ...IfaceOption) error {
i := &Interface{
srcName: srcName,
dstName: dstPrefix,
ns: n,
}
if err := i.processInterfaceOptions(options...); err != nil {
i, err := newInterface(n, srcName, dstPrefix, options...)
if err != nil {
return err
}
if i.master != "" {
i.dstMaster = n.findDst(i.master, true)
if i.dstMaster == "" {
return fmt.Errorf("could not find an appropriate master %q for %q",
i.master, i.srcName)
}
}
n.mu.Lock()
if n.isDefault {
i.dstName = i.srcName

View file

@ -482,20 +482,10 @@ func (n *Namespace) Destroy() error {
func (n *Namespace) Restore(interfaces map[Iface][]IfaceOption, routes []*types.StaticRoute, gw net.IP, gw6 net.IP) error {
// restore interfaces
for iface, opts := range interfaces {
i := &Interface{
srcName: iface.SrcName,
dstName: iface.DstPrefix,
ns: n,
}
if err := i.processInterfaceOptions(opts...); err != nil {
i, err := newInterface(n, iface.SrcName, iface.DstPrefix, opts...)
if err != nil {
return err
}
if i.master != "" {
i.dstMaster = n.findDst(i.master, true)
if i.dstMaster == "" {
return fmt.Errorf("could not find an appropriate master %q for %q", i.master, i.srcName)
}
}
if n.isDefault {
i.dstName = i.srcName
} else {

View file

@ -24,18 +24,6 @@ func WithFamily(family int) NeighOption {
}
}
func (i *Interface) processInterfaceOptions(options ...IfaceOption) error {
for _, opt := range options {
if opt != nil {
// TODO(thaJeztah): use multi-error instead of returning early.
if err := opt(i); err != nil {
return err
}
}
}
return nil
}
// WithIsBridge sets whether the interface is a bridge.
func WithIsBridge(isBridge bool) IfaceOption {
return func(i *Interface) error {