Skip to content

Commit

Permalink
Merge pull request #942 from stgraber/ovn
Browse files Browse the repository at this point in the history
Port more functions to libovsdb
  • Loading branch information
hallyn authored Jun 15, 2024
2 parents 40c8653 + 9cd6ddb commit 1aa35fb
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 60 deletions.
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

0 comments on commit 1aa35fb

Please sign in to comment.