// This does not cover all cases, they should just be added as needed func newMutation(column, mutator string, value interface{}) mutation { switch typedValue := value.(type) { case ovs.UUID: uuidSlice := []ovs.UUID{typedValue} mutateValue, _ := ovs.NewOvsSet(uuidSlice) return ovs.NewMutation(column, mutator, mutateValue) default: var mutateValue interface{} var err error switch reflect.ValueOf(typedValue).Kind() { case reflect.Slice: mutateValue, err = ovs.NewOvsSet(typedValue) case reflect.Map: mutateValue, err = ovs.NewOvsMap(typedValue) default: panic(fmt.Sprintf( "unhandled value in mutation: value %s, type %s", value, typedValue)) } if err != nil { return err } return ovs.NewMutation(column, mutator, mutateValue) } }
// This does not cover all cases, they should just be added as needed func newMutation(column, mutator string, value interface{}) mutation { switch typedValue := value.(type) { case ovs.UUID: uuidSlice := []ovs.UUID{typedValue} mutateValue, err := ovs.NewOvsSet(uuidSlice) if err != nil { // An error can only occur if the input is not a slice panic("newMutation(): an impossible error occurred") } return ovs.NewMutation(column, mutator, mutateValue) default: var mutateValue interface{} var err error switch reflect.ValueOf(typedValue).Kind() { case reflect.Slice: mutateValue, err = ovs.NewOvsSet(typedValue) case reflect.Map: mutateValue, err = ovs.NewOvsMap(typedValue) default: panic(fmt.Sprintf( "unhandled value in mutation: value %s, type %s", value, typedValue)) } if err != nil { return err } return ovs.NewMutation(column, mutator, mutateValue) } }
// CreateAddressSet creates an address set in OVN. func (ovsdb Client) CreateAddressSet(lswitch string, name string, addresses []string) error { addrs, err := ovs.NewOvsSet(addresses) if err != nil { return err } addressRow := map[string]interface{}{ "name": name, "addresses": addrs, } insertOp := ovs.Operation{ Op: "insert", Table: "Address_Set", Row: addressRow, } results, err := ovsdb.transact("OVN_Northbound", insertOp) if err != nil { return fmt.Errorf("transaction error: creating address set on %s: %s", lswitch, err) } return errorCheck(results, 1) }
// CreateLogicalPort creates a new logical port in OVN. func (ovsdb Client) CreateLogicalPort(lswitch, name, mac, ip string) error { addrs, err := ovs.NewOvsSet([]string{fmt.Sprintf("%s %s", mac, ip)}) if err != nil { return err } port := map[string]interface{}{"name": name, "addresses": addrs} insertOp := ovs.Operation{ Op: "insert", Table: "Logical_Switch_Port", Row: port, UUIDName: "qlportadd", } mutateOp := ovs.Operation{ Op: "mutate", Table: "Logical_Switch", Mutations: []interface{}{ newMutation("ports", "insert", ovs.UUID{GoUUID: "qlportadd"}), }, Where: newCondition("name", "==", lswitch), } results, err := ovsdb.transact("OVN_Northbound", insertOp, mutateOp) if err != nil { return fmt.Errorf("transaction error: creating lport %s on %s: %s", name, lswitch, err) } return errorCheck(results, 2) }
func main() { ovs, err := ovsdbgo.Connect("127.0.0.1", 6640) if err != nil { fmt.Println("unable to connect ", err) panic(err) } database := "OpenSwitch" db := ovsdbgo.LoadAll(ovs, database) // add a new bridge named new_bridge transaction := ovsdbgo.Transaction{ovs, db} new_bridge := transaction.InsertRow("Bridge") new_bridge.Set("name", "bridge02") new_bridge_uuid := libovsdb.UUID{ovsdbgo.UuidToUuidName(new_bridge.UUID)} // add reference of new created bridge to "bridges" column in System table for _, sysRow := range db.Tables["System"].Rows { bridges := (sysRow.Data.Fields["bridges"]).(libovsdb.OvsSet) new_bridges := make([]interface{}, len(bridges.GoSet)+1) for ok, uuid := range bridges.GoSet { new_bridges[ok] = uuid } new_bridges[len(new_bridges)-1] = new_bridge_uuid new_bridges_set, _ := libovsdb.NewOvsSet(new_bridges) sysRow.Set("bridges", new_bridges_set) } res, err := transaction.Commit() fmt.Println(res, err) }
// Silently fails :/ func (ovsdber *ovsdber) addOvsVethPort(bridgeName string, portName string, tag uint) error { namedPortUUID := "port" namedIntfUUID := "intf" // intf row to insert intf := make(map[string]interface{}) intf["name"] = portName intf["type"] = `system` insertIntfOp := libovsdb.Operation{ Op: "insert", Table: "Interface", Row: intf, UUIDName: namedIntfUUID, } // port row to insert port := make(map[string]interface{}) port["name"] = portName port["interfaces"] = libovsdb.UUID{namedIntfUUID} insertPortOp := libovsdb.Operation{ Op: "insert", Table: "Port", Row: port, UUIDName: namedPortUUID, } // Inserting a row in Port table requires mutating the bridge table. mutateUUID := []libovsdb.UUID{libovsdb.UUID{namedPortUUID}} mutateSet, _ := libovsdb.NewOvsSet(mutateUUID) mutation := libovsdb.NewMutation("ports", "insert", mutateSet) condition := libovsdb.NewCondition("name", "==", bridgeName) // Mutate operation mutateOp := libovsdb.Operation{ Op: "mutate", Table: "Bridge", Mutations: []interface{}{mutation}, Where: []interface{}{condition}, } operations := []libovsdb.Operation{insertIntfOp, insertPortOp, mutateOp} reply, _ := ovsdber.ovsdb.Transact("Open_vSwitch", operations...) if len(reply) < len(operations) { log.Error("Number of Replies should be atleast equal to number of Operations") } for i, o := range reply { if o.Error != "" && i < len(operations) { msg := fmt.Sprintf("Transaction Failed due to an error ]", o.Error, " details:", o.Details, " in ", operations[i]) return errors.New(msg) } else if o.Error != "" { msg := fmt.Sprintf("Transaction Failed due to an error :", o.Error) return errors.New(msg) } } return nil }
func (ovsdber *ovsdber) addVxlanPort(bridgeName string, portName string, peerAddress string) { namedPortUUID := "port" namedIntfUUID := "intf" options := make(map[string]interface{}) options["remote_ip"] = peerAddress // intf row to insert intf := make(map[string]interface{}) intf["name"] = portName intf["type"] = `vxlan` intf["options"], _ = libovsdb.NewOvsMap(options) insertIntfOp := libovsdb.Operation{ Op: "insert", Table: "Interface", Row: intf, UUIDName: namedIntfUUID, } // port row to insert port := make(map[string]interface{}) port["name"] = portName port["interfaces"] = libovsdb.UUID{namedIntfUUID} insertPortOp := libovsdb.Operation{ Op: "insert", Table: "Port", Row: port, UUIDName: namedPortUUID, } // Inserting a row in Port table requires mutating the bridge table. mutateUUID := []libovsdb.UUID{libovsdb.UUID{namedPortUUID}} mutateSet, _ := libovsdb.NewOvsSet(mutateUUID) mutation := libovsdb.NewMutation("ports", "insert", mutateSet) condition := libovsdb.NewCondition("name", "==", bridgeName) // simple mutate operation mutateOp := libovsdb.Operation{ Op: "mutate", Table: "Bridge", Mutations: []interface{}{mutation}, Where: []interface{}{condition}, } operations := []libovsdb.Operation{insertIntfOp, insertPortOp, mutateOp} reply, _ := ovsdber.ovsdb.Transact("Open_vSwitch", operations...) if len(reply) < len(operations) { fmt.Println("Number of Replies should be atleast equal to number of Operations") } for i, o := range reply { if o.Error != "" && i < len(operations) { fmt.Println("Transaction Failed due to an error :", o.Error, " details:", o.Details, " in ", operations[i]) } else if o.Error != "" { fmt.Println("Transaction Failed due to an error :", o.Error) } } }
func insertRoute(vrfId uuid.UUID, opsRoute map[string]interface{}) (ovsdb.Operation, error) { v := []ovsdb.UUID{ovsdb.UUID{vrfId.String()}} vrfSet, _ := ovsdb.NewOvsSet(v) opsRoute["vrf"] = vrfSet nexthop := []ovsdb.UUID{ovsdb.UUID{NEXTHOP_TRANSACT_NUUID}} nexthopSet, _ := ovsdb.NewOvsSet(nexthop) opsRoute["bgp_nexthops"] = nexthopSet attrMap, err := ovsdb.NewOvsMap(opsRoute["path_attributes"]) if err != nil { return ovsdb.Operation{}, err } opsRoute["path_attributes"] = attrMap insRouteOp := ovsdb.Operation{ Op: "insert", Table: "BGP_Route", Row: opsRoute, UUIDName: ROUTE_TRANSACT_NUUID, } return insRouteOp, nil }
func createBridge(ovs *libovsdb.OvsdbClient, bridgeName string) { namedUuid := "gopher" // bridge row to insert bridge := make(map[string]interface{}) bridge["name"] = bridgeName // simple insert operation insertOp := libovsdb.Operation{ Op: "insert", Table: "Bridge", Row: bridge, UUIDName: namedUuid, } // Inserting a Bridge row in Bridge table requires mutating the open_vswitch table. mutateUuid := []libovsdb.UUID{libovsdb.UUID{namedUuid}} mutateSet, _ := libovsdb.NewOvsSet(mutateUuid) mutation := libovsdb.NewMutation("bridges", "insert", mutateSet) condition := libovsdb.NewCondition("_uuid", "==", libovsdb.UUID{getRootUuid()}) // simple mutate operation mutateOp := libovsdb.Operation{ Op: "mutate", Table: "Open_vSwitch", Mutations: []interface{}{mutation}, Where: []interface{}{condition}, } operations := []libovsdb.Operation{insertOp, mutateOp} reply, _ := ovs.Transact("Open_vSwitch", operations...) if len(reply) < len(operations) { fmt.Println("Number of Replies should be atleast equal to number of Operations") } ok := true for i, o := range reply { if o.Error != "" && i < len(operations) { fmt.Println("Transaction Failed due to an error :", o.Error, " details:", o.Details, " in ", operations[i]) ok = false } else if o.Error != "" { fmt.Println("Transaction Failed due to an error :", o.Error) ok = false } } if ok { fmt.Println("Bridge Addition Successful : ", reply[0].UUID.GoUuid) } }
func (ovsdber *ovsdber) deletePort(bridgeName string, portName string) error { condition := libovsdb.NewCondition("name", "==", portName) deleteOp := libovsdb.Operation{ Op: "delete", Table: "Port", Where: []interface{}{condition}, } portUUID := portUUIDForName(portName) if portUUID == "" { log.Error("Unable to find a matching Port : ", portName) return fmt.Errorf("Unable to find a matching Port : [ %s ]", portName) } // Deleting a Bridge row in Bridge table requires mutating the open_vswitch table. mutateUUID := []libovsdb.UUID{libovsdb.UUID{portUUID}} mutateSet, _ := libovsdb.NewOvsSet(mutateUUID) mutation := libovsdb.NewMutation("ports", "delete", mutateSet) condition = libovsdb.NewCondition("name", "==", bridgeName) // simple mutate operation mutateOp := libovsdb.Operation{ Op: "mutate", Table: "Bridge", Mutations: []interface{}{mutation}, Where: []interface{}{condition}, } operations := []libovsdb.Operation{deleteOp, mutateOp} reply, _ := ovsdber.ovsdb.Transact("Open_vSwitch", operations...) if len(reply) < len(operations) { log.Error("Number of Replies should be atleast equal to number of Operations") return fmt.Errorf("Number of Replies should be atleast equal to number of Operations") } for i, o := range reply { if o.Error != "" && i < len(operations) { log.Error("Transaction Failed due to an error :", o.Error, " in ", operations[i]) return fmt.Errorf("Transaction Failed due to an error: %s in %v", o.Error, operations[i]) } else if o.Error != "" { log.Error("Transaction Failed due to an error :", o.Error) return fmt.Errorf("Transaction Failed due to an error %s", o.Error) } } return nil }
// deleteBridge deletes the OVS bridge func (ovsdber *ovsdber) deleteBridge(bridgeName string) error { namedBridgeUUID := "bridge" // simple delete operation condition := libovsdb.NewCondition("name", "==", bridgeName) deleteOp := libovsdb.Operation{ Op: "delete", Table: "Bridge", Where: []interface{}{condition}, } // Deleting a Bridge row in Bridge table requires mutating the open_vswitch table. mutateUUID := []libovsdb.UUID{libovsdb.UUID{namedBridgeUUID}} mutateSet, _ := libovsdb.NewOvsSet(mutateUUID) mutation := libovsdb.NewMutation("bridges", "delete", mutateSet) // simple mutate operation mutateOp := libovsdb.Operation{ Op: "mutate", Table: "Open_vSwitch", Mutations: []interface{}{mutation}, Where: []interface{}{condition}, } operations := []libovsdb.Operation{deleteOp, mutateOp} reply, _ := ovsdber.ovsdb.Transact("Open_vSwitch", operations...) if len(reply) < len(operations) { log.Error("Number of Replies should be atleast equal to number of Operations") } for i, o := range reply { if o.Error != "" && i < len(operations) { log.Error("Transaction Failed due to an error :", o.Error, " in ", operations[i]) errMsg := fmt.Sprintf("Transaction Failed due to an error: %s in operation: %v", o.Error, operations[i]) return errors.New(errMsg) } else if o.Error != "" { errMsg := fmt.Sprintf("Transaction Failed due to an error : %s", o.Error) return errors.New(errMsg) } } log.Debugf("OVSDB delete bridge transaction succesful") return nil }
// CreateOFPort creates an openflow port on specified bridge // // A port cannot be created without an interface, that is why the "default" // interface (one with the same name as the port) is created along with it. func (ovsdb Client) CreateOFPort(bridge, name string) error { var ops []ovs.Operation ops = append(ops, ovs.Operation{ Op: "insert", Table: "Interface", Row: Row{"name": name}, UUIDName: "diifaceadd", }) ifaces, err := ovs.NewOvsSet([]ovs.UUID{{GoUUID: "diifaceadd"}}) if err != nil { return err } ops = append(ops, ovs.Operation{ Op: "insert", Table: "Port", Row: Row{"name": name, "interfaces": ifaces}, UUIDName: "diportadd", }) ops = append(ops, ovs.Operation{ Op: "mutate", Table: "Bridge", Mutations: []interface{}{ newMutation("ports", "insert", ovs.UUID{GoUUID: "diportadd"}), }, Where: []interface{}{newCondition("name", "==", bridge)}, }) results, err := ovsdb.Transact("Open_vSwitch", ops...) if err != nil { return fmt.Errorf( "transaction error creating openflow port %s within %s: %s", name, bridge, err) } if err := errorCheck(results, 2, 1); err != nil { return fmt.Errorf("error creating openflow port %s within %s: %s", name, bridge, err) } return nil }
// CreatePort creates a new logical port in OVN. func (ovsdb Client) CreatePort(lswitch, name, mac, ip string) error { // OVN Uses name an index into the Logical_Port table so, we need to check // no port called name already exists. This isn't strictly necessary, but it // makes our lives easier. rows, err := ovsdb.selectRows("OVN_Northbound", "Logical_Port", newCondition("name", "==", name)) if err != nil { return err } if len(rows) > 0 { return &ExistError{fmt.Sprintf("port %s already exists", name)} } port := make(map[string]interface{}) port["name"] = name addrs, err := ovs.NewOvsSet([]string{fmt.Sprintf("%s %s", mac, ip)}) if err != nil { return err } port["addresses"] = addrs insertOp := ovs.Operation{ Op: "insert", Table: "Logical_Port", Row: port, UUIDName: "dilportadd", } mutateOp := ovs.Operation{ Op: "mutate", Table: "Logical_Switch", Mutations: []interface{}{ newMutation("ports", "insert", ovs.UUID{GoUUID: "dilportadd"}), }, Where: []interface{}{newCondition("name", "==", lswitch)}, } results, err := ovsdb.Transact("OVN_Northbound", insertOp, mutateOp) if err != nil { return errors.New("transaction error") } return errorCheck(results, 2, 1) }
// CreateInterface creates an openflow port on specified bridge. // // A port cannot be created without an interface, that is why the "default" // interface (one with the same name as the port) is created along with it. func (ovsdb Client) CreateInterface(bridge, name string) error { var ops []ovs.Operation ops = append(ops, ovs.Operation{ Op: "insert", Table: "Interface", Row: row{"name": name}, UUIDName: "qifaceadd", }) ifaces, err := ovs.NewOvsSet([]ovs.UUID{{GoUUID: "qifaceadd"}}) if err != nil { return err } ops = append(ops, ovs.Operation{ Op: "insert", Table: "Port", Row: row{"name": name, "interfaces": ifaces}, UUIDName: "qportadd", }) ops = append(ops, ovs.Operation{ Op: "mutate", Table: "Bridge", Mutations: []interface{}{ newMutation("ports", "insert", ovs.UUID{GoUUID: "qportadd"}), }, Where: newCondition("name", "==", bridge), }) results, err := ovsdb.transact("Open_vSwitch", ops...) if err != nil { return fmt.Errorf("transaction error: creating interface %s: %s", name, err) } return errorCheck(results, len(ops)) }
// createOvsdbBridge creates the OVS bridge func (ovsdber *ovsdber) createOvsdbBridge(bridgeName string) error { namedBridgeUUID := "bridge" namedPortUUID := "port" namedIntfUUID := "intf" // intf row to insert intf := make(map[string]interface{}) intf["name"] = bridgeName intf["type"] = `internal` insertIntfOp := libovsdb.Operation{ Op: "insert", Table: "Interface", Row: intf, UUIDName: namedIntfUUID, } // Port row to insert port := make(map[string]interface{}) port["name"] = bridgeName port["interfaces"] = libovsdb.UUID{namedIntfUUID} insertPortOp := libovsdb.Operation{ Op: "insert", Table: "Port", Row: port, UUIDName: namedPortUUID, } // Bridge row to insert bridge := make(map[string]interface{}) bridge["name"] = bridgeName bridge["stp_enable"] = false bridge["ports"] = libovsdb.UUID{namedPortUUID} insertBridgeOp := libovsdb.Operation{ Op: "insert", Table: "Bridge", Row: bridge, UUIDName: namedBridgeUUID, } // Inserting a Bridge row in Bridge table requires mutating the open_vswitch table. mutateUUID := []libovsdb.UUID{libovsdb.UUID{namedBridgeUUID}} mutateSet, _ := libovsdb.NewOvsSet(mutateUUID) mutation := libovsdb.NewMutation("bridges", "insert", mutateSet) condition := libovsdb.NewCondition("_uuid", "==", libovsdb.UUID{ovsdber.getRootUUID()}) // Mutate operation mutateOp := libovsdb.Operation{ Op: "mutate", Table: "Open_vSwitch", Mutations: []interface{}{mutation}, Where: []interface{}{condition}, } operations := []libovsdb.Operation{insertIntfOp, insertPortOp, insertBridgeOp, mutateOp} reply, _ := ovsdber.ovsdb.Transact("Open_vSwitch", operations...) if len(reply) < len(operations) { return errors.New("Number of Replies should be atleast equal to number of Operations") } for i, o := range reply { if o.Error != "" && i < len(operations) { return errors.New("Transaction Failed due to an error :" + o.Error + " details : " + o.Details) } else if o.Error != "" { return errors.New("Transaction Failed due to an error :" + o.Error + " details : " + o.Details) } } return nil }