Skip to content
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

Port more functions to libovsdb #942

Merged
merged 7 commits into from
Jun 15, 2024
2 changes: 1 addition & 1 deletion internal/server/device/nic_ovn.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ func (d *nicOVN) Start() (*deviceConfig.RunConfig, error) {

// Add post start hook for setting logical switch port chassis once instance has been started.
runConf.PostHooks = append(runConf.PostHooks, func() error {
err := d.state.OVNNB.LogicalSwitchPortOptionsSet(logicalPortName, map[string]string{"requested-chassis": chassisID})
err := d.state.OVNNB.UpdateLogicalSwitchPortOptions(context.TODO(), logicalPortName, map[string]string{"requested-chassis": chassisID})
if err != nil {
return fmt.Errorf("Failed setting logical switch port chassis ID: %w", err)
}
Expand Down
18 changes: 9 additions & 9 deletions internal/server/network/acl/acl_ovn.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,12 @@ func OVNEnsureACLs(s *state.State, l logger.Logger, client *ovn.NB, aclProjectNa
if portGroupUUID == "" {
l.Debug("Creating empty referenced ACL OVN port group", logger.Ctx{"networkACL": aclName, "portGroup": portGroupName})

err := client.PortGroupAdd(projectID, portGroupName, "", "")
err := client.CreatePortGroup(context.TODO(), projectID, portGroupName, "", "")
if err != nil {
return nil, fmt.Errorf("Failed creating port group %q for referenced security ACL %q setup: %w", portGroupName, aclName, err)
}

revert.Add(func() { _ = client.PortGroupDelete(portGroupName) })
revert.Add(func() { _ = client.DeletePortGroup(context.TODO(), portGroupName) })
}
}

Expand All @@ -237,25 +237,25 @@ func OVNEnsureACLs(s *state.State, l logger.Logger, client *ovn.NB, aclProjectNa
portGroupName := OVNACLPortGroupName(aclNameIDs[aclStatus.name])
l.Debug("Creating ACL OVN port group", logger.Ctx{"networkACL": aclStatus.name, "portGroup": portGroupName})

err := client.PortGroupAdd(projectID, portGroupName, "", "")
err := client.CreatePortGroup(context.TODO(), projectID, portGroupName, "", "")
if err != nil {
return nil, fmt.Errorf("Failed creating port group %q for security ACL %q setup: %w", portGroupName, aclStatus.name, err)
}

revert.Add(func() { _ = client.PortGroupDelete(portGroupName) })
revert.Add(func() { _ = client.DeletePortGroup(context.TODO(), portGroupName) })

// Create any per-ACL-per-network port groups needed.
for _, aclNet := range aclNets {
netPortGroupName := OVNACLNetworkPortGroupName(aclNameIDs[aclStatus.name], aclNet.ID)
l.Debug("Creating ACL OVN network port group", logger.Ctx{"networkACL": aclStatus.name, "portGroup": netPortGroupName})

// Create OVN network specific port group and link it to switch by adding the router port.
err = client.PortGroupAdd(projectID, netPortGroupName, portGroupName, OVNIntSwitchName(aclNet.ID), OVNIntSwitchRouterPortName(aclNet.ID))
err = client.CreatePortGroup(context.TODO(), projectID, netPortGroupName, portGroupName, OVNIntSwitchName(aclNet.ID), OVNIntSwitchRouterPortName(aclNet.ID))
if err != nil {
return nil, fmt.Errorf("Failed creating port group %q for security ACL %q and network %q setup: %w", portGroupName, aclStatus.name, aclNet.Name, err)
}

revert.Add(func() { _ = client.PortGroupDelete(netPortGroupName) })
revert.Add(func() { _ = client.DeletePortGroup(context.TODO(), netPortGroupName) })
}

// Now apply our ACL rules to port group (and any per-ACL-per-network port groups needed).
Expand All @@ -276,12 +276,12 @@ func OVNEnsureACLs(s *state.State, l logger.Logger, client *ovn.NB, aclProjectNa
l.Debug("Creating ACL OVN network port group", logger.Ctx{"networkACL": aclStatus.name, "portGroup": netPortGroupName})

// Create OVN network specific port group and link it to switch by adding the router port.
err := client.PortGroupAdd(projectID, netPortGroupName, portGroupName, OVNIntSwitchName(aclNet.ID), OVNIntSwitchRouterPortName(aclNet.ID))
err := client.CreatePortGroup(context.TODO(), projectID, netPortGroupName, portGroupName, OVNIntSwitchName(aclNet.ID), OVNIntSwitchRouterPortName(aclNet.ID))
if err != nil {
return nil, fmt.Errorf("Failed creating port group %q for security ACL %q and network %q setup: %w", portGroupName, aclStatus.name, aclNet.Name, err)
}

revert.Add(func() { _ = client.PortGroupDelete(netPortGroupName) })
revert.Add(func() { _ = client.DeletePortGroup(context.TODO(), netPortGroupName) })
}

// If aclInfo has been loaded, then we should use it to apply ACL rules to the existing port group
Expand Down Expand Up @@ -974,7 +974,7 @@ func OVNPortGroupDeleteIfUnused(s *state.State, l logger.Logger, client *ovn.NB,
}

if len(removePortGroups) > 0 {
err = client.PortGroupDelete(removePortGroups...)
err = client.DeletePortGroup(context.TODO(), removePortGroups...)
if err != nil {
return fmt.Errorf("Failed to delete unused OVN port groups: %w", err)
}
Expand Down
10 changes: 5 additions & 5 deletions internal/server/network/driver_ovn.go
Original file line number Diff line number Diff line change
Expand Up @@ -2609,7 +2609,7 @@ func (n *ovn) ensureNetworkPortGroup(projectID int64) error {
if intPortGroupUUID == "" {
// Create internal port group and associate it with the logical switch, so that it will be
// removed when the logical switch is removed.
err = n.state.OVNNB.PortGroupAdd(projectID, intPortGroupName, "", n.getIntSwitchName())
err = n.state.OVNNB.CreatePortGroup(context.TODO(), projectID, intPortGroupName, "", n.getIntSwitchName())
if err != nil {
return fmt.Errorf("Failed creating port group %q for network %q setup: %w", intPortGroupName, n.Name(), err)
}
Expand Down Expand Up @@ -3081,7 +3081,7 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re
removeChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{}

// Get list of active switch ports (avoids repeated querying of OVN NB).
activePorts, err := n.state.OVNNB.LogicalSwitchPorts(n.getIntSwitchName())
activePorts, err := n.state.OVNNB.GetLogicalSwitchPorts(context.TODO(), n.getIntSwitchName())
if err != nil {
return fmt.Errorf("Failed getting active ports: %w", err)
}
Expand Down Expand Up @@ -4439,7 +4439,7 @@ func (n *ovn) handleDependencyChange(uplinkName string, uplinkConfig map[string]

if slices.Contains([]string{"l2proxy", ""}, uplinkConfig["ovn.ingress_mode"]) {
// Get list of active switch ports (avoids repeated querying of OVN NB).
activePorts, err := n.state.OVNNB.LogicalSwitchPorts(n.getIntSwitchName())
activePorts, err := n.state.OVNNB.GetLogicalSwitchPorts(context.TODO(), n.getIntSwitchName())
if err != nil {
return fmt.Errorf("Failed getting active ports: %w", err)
}
Expand Down Expand Up @@ -5359,7 +5359,7 @@ func (n *ovn) localPeerCreate(peer api.NetworkPeersPost) error {
return fmt.Errorf("Failed applying local router security policy: %w", err)
}

activeLocalNICPorts, err := n.state.OVNNB.LogicalSwitchPorts(n.getIntSwitchName())
activeLocalNICPorts, err := n.state.OVNNB.GetLogicalSwitchPorts(context.TODO(), n.getIntSwitchName())
if err != nil {
return fmt.Errorf("Failed getting active NIC ports: %w", err)
}
Expand Down Expand Up @@ -5786,7 +5786,7 @@ func (n *ovn) peerSetup(ovnnb *networkOVN.NB, targetOVNNet *ovn, opts networkOVN
}

// Get list of active switch ports (avoids repeated querying of OVN NB).
activeTargetNICPorts, err := n.state.OVNNB.LogicalSwitchPorts(targetOVNNet.getIntSwitchName())
activeTargetNICPorts, err := n.state.OVNNB.GetLogicalSwitchPorts(context.TODO(), targetOVNNet.getIntSwitchName())
if err != nil {
return fmt.Errorf("Failed getting active NIC ports: %w", err)
}
Expand Down
170 changes: 125 additions & 45 deletions internal/server/network/ovn/ovn_nb_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1445,42 +1445,46 @@ func (o *NB) LogicalSwitchSetACLRules(switchName OVNSwitch, aclRules ...OVNACLRu
}

// logicalSwitchPortACLRules returns the ACL rule UUIDs belonging to a logical switch port.
func (o *NB) logicalSwitchPortACLRules(portName OVNSwitchPort) ([]string, error) {
// Remove any existing rules assigned to the entity.
output, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "acl",
fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitchPort, string(portName)),
)
func (o *NB) logicalSwitchPortACLRules(ctx context.Context, portName OVNSwitchPort) ([]string, error) {
acls := []ovnNB.ACL{}

err := o.client.WhereCache(func(acl *ovnNB.ACL) bool {
return acl.ExternalIDs != nil && acl.ExternalIDs[ovnExtIDIncusSwitchPort] == string(portName)
}).List(ctx, &acls)
if err != nil {
return nil, err
}

ruleUUIDs := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true)
ruleUUIDs := []string{}
for _, acl := range acls {
ruleUUIDs = append(ruleUUIDs, acl.UUID)
}

return ruleUUIDs, nil
}

// LogicalSwitchPorts returns a map of logical switch ports (name and UUID) for a switch.
// GetLogicalSwitchPorts returns a map of logical switch ports (name and UUID) for a switch.
// Includes non-instance ports, such as the router port.
func (o *NB) LogicalSwitchPorts(switchName OVNSwitch) (map[OVNSwitchPort]OVNSwitchPortUUID, error) {
output, err := o.nbctl("lsp-list", string(switchName))
func (o *NB) GetLogicalSwitchPorts(ctx context.Context, switchName OVNSwitch) (map[OVNSwitchPort]OVNSwitchPortUUID, error) {
// Get the logical switch.
logicalSwitch, err := o.GetLogicalSwitch(ctx, switchName)
if err != nil {
return nil, err
}

lines := util.SplitNTrimSpace(strings.TrimSpace(output), "\n", -1, true)
ports := make(map[OVNSwitchPort]OVNSwitchPortUUID, len(lines))

for _, line := range lines {
// E.g. "c709c4a8-ef3f-4ffe-a45a-c75295eb2698 (incus-net3-instance-fc933d65-0900-46b0-b5f2-4d323342e755-eth0)"
fields := strings.Fields(line)
ports := make(map[OVNSwitchPort]OVNSwitchPortUUID, len(logicalSwitch.Ports))
for _, portUUID := range logicalSwitch.Ports {
// Get the logical switch port.
lsp := ovnNB.LogicalSwitchPort{
UUID: portUUID,
}

if len(fields) != 2 {
return nil, fmt.Errorf("Unrecognised switch port item output %q", line)
err := o.get(ctx, &lsp)
if err != nil {
return nil, err
}

portUUID := OVNSwitchPortUUID(fields[0])
portName := OVNSwitchPort(strings.TrimPrefix(strings.TrimSuffix(fields[1], ")"), "("))
ports[portName] = portUUID
ports[OVNSwitchPort(lsp.Name)] = OVNSwitchPortUUID(lsp.UUID)
}

return ports, nil
Expand Down Expand Up @@ -1739,15 +1743,40 @@ func (o *NB) GetLogicalSwitchPortLocation(ctx context.Context, portName OVNSwitc
return val, nil
}

// LogicalSwitchPortOptionsSet sets the options for a logical switch port.
func (o *NB) LogicalSwitchPortOptionsSet(portName OVNSwitchPort, options map[string]string) error {
args := []string{"lsp-set-options", string(portName)}
// UpdateLogicalSwitchPortOptions sets the options for a logical switch port.
func (o *NB) UpdateLogicalSwitchPortOptions(ctx context.Context, portName OVNSwitchPort, options map[string]string) error {
// Get the logical switch port.
lsp := ovnNB.LogicalSwitchPort{
Name: string(portName),
}

err := o.get(ctx, &lsp)
if err != nil {
return err
}

// Apply the changes.
if lsp.Options == nil {
lsp.Options = map[string]string{}
}

for key, value := range options {
args = append(args, fmt.Sprintf("%s=%s", key, value))
lsp.Options[key] = value
}

_, err := o.nbctl(args...)
// Update the record.
operations, err := o.client.Where(&lsp).Update(&lsp)
if err != nil {
return err
}

// Apply the changes.
resp, err := o.client.Transact(ctx, operations...)
if err != nil {
return err
}

_, err = ovsdb.CheckOperationResults(resp, operations)
if err != nil {
return err
}
Expand Down Expand Up @@ -1953,7 +1982,7 @@ func (o *NB) DeleteLogicalSwitchPort(ctx context.Context, switchName OVNSwitch,
// LogicalSwitchPortCleanup deletes the named logical switch port and its associated config.
func (o *NB) LogicalSwitchPortCleanup(portName OVNSwitchPort, switchName OVNSwitch, switchPortGroupName OVNPortGroup, dnsUUID OVNDNSUUID) error {
// Remove any existing rules assigned to the entity.
removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName)
removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(context.TODO(), portName)
if err != nil {
return err
}
Expand Down Expand Up @@ -2209,48 +2238,99 @@ func (o *NB) GetPortGroupInfo(ctx context.Context, portGroupName OVNPortGroup) (
return OVNPortGroupUUID(pg.UUID), len(pg.ACLs) > 0, nil
}

// PortGroupAdd creates a new port group and optionally adds logical switch ports to the group.
func (o *NB) PortGroupAdd(projectID int64, portGroupName OVNPortGroup, associatedPortGroup OVNPortGroup, associatedSwitch OVNSwitch, initialPortMembers ...OVNSwitchPort) error {
args := []string{"pg-add", string(portGroupName)}
// CreatePortGroup creates a new port group and optionally adds logical switch ports to the group.
func (o *NB) CreatePortGroup(ctx context.Context, projectID int64, portGroupName OVNPortGroup, associatedPortGroup OVNPortGroup, associatedSwitch OVNSwitch, initialPortMembers ...OVNSwitchPort) error {
// Resolve the initial members.
members := []string{}
for _, portName := range initialPortMembers {
args = append(args, string(portName))
lsp := ovnNB.LogicalSwitchPort{
Name: string(portName),
}

err := o.get(ctx, &lsp)
if err != nil {
return err
}

members = append(members, lsp.UUID)
}

args = append(args, "--", "set", "port_group", string(portGroupName),
fmt.Sprintf("external_ids:%s=%d", ovnExtIDIncusProjectID, projectID),
)
// Create the port group.
pg := ovnNB.PortGroup{
Name: string(portGroupName),
Ports: members,
ExternalIDs: map[string]string{
ovnExtIDIncusProjectID: fmt.Sprintf("%d", projectID),
},
}

if associatedPortGroup != "" || associatedSwitch != "" {
if associatedPortGroup != "" {
args = append(args, fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusPortGroup, associatedPortGroup))
pg.ExternalIDs[ovnExtIDIncusPortGroup] = string(associatedPortGroup)
}

if associatedSwitch != "" {
args = append(args, fmt.Sprintf("external_ids:%s=%s", ovnExtIDIncusSwitch, associatedSwitch))
pg.ExternalIDs[ovnExtIDIncusSwitch] = string(associatedSwitch)
}
}

_, err := o.nbctl(args...)
// Create the record.
operations, err := o.client.Create(&pg)
if err != nil {
return err
}

// Apply the changes.
resp, err := o.client.Transact(ctx, operations...)
if err != nil {
return err
}

_, err = ovsdb.CheckOperationResults(resp, operations)
if err != nil {
return err
}

return nil
}

// PortGroupDelete deletes port groups along with their ACL rules.
func (o *NB) PortGroupDelete(portGroupNames ...OVNPortGroup) error {
args := make([]string, 0)
// DeletePortGroup deletes port groups along with their ACL rules.
func (o *NB) DeletePortGroup(ctx context.Context, portGroupNames ...OVNPortGroup) error {
operations := []ovsdb.Operation{}

for _, portGroupName := range portGroupNames {
if len(args) > 0 {
args = append(args, "--")
pg := ovnNB.PortGroup{
Name: string(portGroupName),
}

args = append(args, "--if-exists", "destroy", "port_group", string(portGroupName))
err := o.get(ctx, &pg)
if err != nil {
if err == ErrNotFound {
// Already gone.
continue
}
}

deleteOps, err := o.client.Where(&pg).Delete()
if err != nil {
return err
}

operations = append(operations, deleteOps...)
}

_, err := o.nbctl(args...)
// Check if we have anything to do.
if len(operations) == 0 {
return nil
}

// Apply the changes.
resp, err := o.client.Transact(ctx, operations...)
if err != nil {
return err
}

_, err = ovsdb.CheckOperationResults(resp, operations)
if err != nil {
return err
}
Expand Down Expand Up @@ -2387,7 +2467,7 @@ func (o *NB) aclRuleDeleteAppendArgs(args []string, entityTable string, entityNa
// Any existing rules for that logical switch port in the port group are removed.
func (o *NB) PortGroupPortSetACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort, aclRules ...OVNACLRule) error {
// Remove any existing rules assigned to the entity.
removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName)
removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(context.TODO(), portName)
if err != nil {
return err
}
Expand All @@ -2413,7 +2493,7 @@ func (o *NB) PortGroupPortSetACLRules(portGroupName OVNPortGroup, portName OVNSw
// PortGroupPortClearACLRules clears any rules assigned to the logical switch port in the specified port group.
func (o *NB) PortGroupPortClearACLRules(portGroupName OVNPortGroup, portName OVNSwitchPort) error {
// Remove any existing rules assigned to the entity.
removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(portName)
removeACLRuleUUIDs, err := o.logicalSwitchPortACLRules(context.TODO(), portName)
if err != nil {
return err
}
Expand Down
Loading