diff --git a/ofctrl/fgraphFlow.go b/ofctrl/fgraphFlow.go index 47f3cd0a..5e3c645d 100644 --- a/ofctrl/fgraphFlow.go +++ b/ofctrl/fgraphFlow.go @@ -67,6 +67,12 @@ type FlowMatch struct { UdpSrcPortMask uint16 // UDP source port mask UdpDstPort uint16 // UDP dest port UdpDstPortMask uint16 // UDP dest port mask + Icmp6Code *uint8 // ICMPv6 code + Icmp6Type *uint8 // ICMPv6 type + NdTarget *net.IP // ICMPv6 Neighbor Discovery Target + NdTargetMask *net.IP // Mask for ICMPv6 Neighbor Discovery Target + NdSll *net.HardwareAddr // ICMPv6 Neighbor Discovery Source Ethernet Address + NdTll *net.HardwareAddr // ICMPv6 Neighbor DIscovery Target Ethernet Address Metadata *uint64 // OVS metadata MetadataMask *uint64 // Metadata mask TunnelId uint64 // Vxlan Tunnel id i.e. VNI @@ -492,6 +498,35 @@ func (self *Flow) xlateMatch() openflow13.Match { } } + if self.Match.Icmp6Code != nil { + icmp6CodeField, _ := openflow13.FindFieldHeaderByName("NXM_NX_ICMPV6_CODE", false) + icmp6CodeField.Value = &openflow13.IcmpCodeField{Code: *self.Match.Icmp6Code} + ofMatch.AddField(*icmp6CodeField) + } + if self.Match.Icmp6Type != nil { + icmp6TypeField, _ := openflow13.FindFieldHeaderByName("NXM_NX_ICMPV6_Type", false) + icmp6TypeField.Value = &openflow13.IcmpTypeField{Type: *self.Match.Icmp6Type} + ofMatch.AddField(*icmp6TypeField) + } + if self.Match.NdTarget != nil { + ndTargetField, _ := openflow13.FindFieldHeaderByName("NXM_NX_ND_TARGET", self.Match.NdTargetMask != nil) + ndTargetField.Value = &openflow13.Ipv6DstField{Ipv6Dst: *self.Match.NdTarget} + if self.Match.NdTargetMask != nil { + ndTargetField.Mask = &openflow13.Ipv6DstField{Ipv6Dst: *self.Match.NdTargetMask} + } + ofMatch.AddField(*ndTargetField) + } + if self.Match.NdSll != nil { + ndSllField, _ := openflow13.FindFieldHeaderByName("NXM_NX_ND_SLL", false) + ndSllField.Value = &openflow13.EthSrcField{EthSrc: *self.Match.NdSll} + ofMatch.AddField(*ndSllField) + } + if self.Match.NdTll != nil { + ndTllField, _ := openflow13.FindFieldHeaderByName("NXM_NX_ND_SLL", false) + ndTllField.Value = &openflow13.EthDstField{EthDst: *self.Match.NdTll} + ofMatch.AddField(*ndTllField) + } + return *ofMatch } @@ -680,6 +715,17 @@ func (self *Flow) Next(elem FgraphElem) error { return self.install() } +func (self *Flow) ForceAddInstall() error { + self.lock.Lock() + defer self.lock.Unlock() + + // clear installed flag + self.isInstalled = false + + // Install the flow entry + return self.install() +} + func (self *Flow) SetConntrack(connTrackAction *ConnTrackAction) error { self.flowActions = append(self.flowActions, connTrackAction) diff --git a/ofctrl/ofctrl.go b/ofctrl/ofctrl.go index 7cebd6ee..92ff17f9 100755 --- a/ofctrl/ofctrl.go +++ b/ofctrl/ofctrl.go @@ -382,18 +382,30 @@ func setDatapathID(conn *ovsdb.OvsdbClient, bridgeName string) error { h := sha256.New() h.Write([]byte(bridgeName)) datapathID := h.Sum(nil)[:8] + mac := net.HardwareAddr(h.Sum(nil)[:6]) + mac[0] &^= 1 config, _ := ovsdb.NewOvsMap(map[string]string{"datapath-id": hex.EncodeToString(datapathID)}) - operation := ovsdb.Operation{ + operDpid := ovsdb.Operation{ Op: "mutate", Table: "Bridge", Where: []interface{}{[]interface{}{"name", "==", bridgeName}}, Mutations: []interface{}{[]interface{}{"other_config", "insert", config}}, // never update the datapath id } - _, err := ovsdbTransact(conn, "Open_vSwitch", operation) + operMac := ovsdb.Operation{ + Op: "mutate", + Table: "Port", + Where: []interface{}{[]interface{}{"name", "==", bridgeName}}, + Mutations: []interface{}{[]interface{}{"mac", "insert", mac.String()}}, + } + if _, err := ovsdbTransact(conn, "Open_vSwitch", operDpid, operMac); err != nil { + return err + } + + log.Infof("bridge %s internal port mac (if exist) has been set to %s", bridgeName, mac.String()) log.Infof("bridge %s datapath id has been set to %s", bridgeName, hex.EncodeToString(datapathID)) - return err + return nil } func ovsdbTransact(client *ovsdb.OvsdbClient, database string, operation ...ovsdb.Operation) ([]ovsdb.OperationResult, error) { diff --git a/ofctrl/ofctrl_test.go b/ofctrl/ofctrl_test.go index 0e51a268..0e73a131 100644 --- a/ofctrl/ofctrl_test.go +++ b/ofctrl/ofctrl_test.go @@ -858,6 +858,10 @@ func TestNewOFController(t *testing.T) { driver := ovsdbDriver.NewOvsDriver(bridgeName) defer driver.Delete() + if err := driver.CreatePort(bridgeName, "internal", 0); err != nil { + t.Fatalf("fail to create default internal port : %s", err) + } + _ = NewOFController(&ofActor, uint16(rand.Intn(1024)), driver.OVSClient(), bridgeName) //wait for 2sec @@ -871,4 +875,8 @@ func TestNewOFController(t *testing.T) { if config["datapath-id"] == "" { t.Fatalf("datapath id must be set before connect to switch") } + + if mac, err := driver.GetInternalPortMac(); err != nil || mac == "" { + t.Fatalf("internal port mac must be set before connect to switch, err = %s", err) + } } diff --git a/ovsdbDriver/ovsdbDriver.go b/ovsdbDriver/ovsdbDriver.go index c96cffae..8d42c311 100644 --- a/ovsdbDriver/ovsdbDriver.go +++ b/ovsdbDriver/ovsdbDriver.go @@ -48,8 +48,7 @@ func NewOvsDriver(bridgeName string) *OvsDriver { _ = ovs.MonitorAll("Open_vSwitch", "") // Create the default bridge instance - err = ovsDriver.CreateBridge(ovsDriver.OvsBridgeName) - if err != nil { + if err = ovsDriver.CreateBridge(ovsDriver.OvsBridgeName); err != nil { log.Fatalf("Error creating the default bridge. Err: %v", err) } @@ -183,9 +182,9 @@ func (self *OvsDriver) ovsdbTransact(ops []libovsdb.Operation) error { // Parse reply and look for errors for i, o := range reply { if o.Error != "" && i < len(ops) { - return errors.New("OVS Transaction failed err " + o.Error + "Details: " + o.Details) + return errors.New("OVS Transaction failed err " + o.Error + "Details: " + o.Details + " UUID: " + o.UUID.GoUuid) } else if o.Error != "" { - return errors.New("OVS Transaction failed err " + o.Error + "Details: " + o.Details) + return errors.New("OVS Transaction failed err " + o.Error + "Details: " + o.Details + " UUID: " + o.UUID.GoUuid) } } @@ -345,6 +344,31 @@ func (self *OvsDriver) GetOtherConfig() (map[string]string, error) { return buildMapFromOVSDBMap(externalIds), nil } +func (self *OvsDriver) GetInternalPortMac() (string, error) { + selectOper := libovsdb.Operation{ + Op: "select", + Table: "Port", + Where: []interface{}{[]interface{}{"name", "==", self.OvsBridgeName}}, + Columns: []string{"mac"}, + } + + opers := []libovsdb.Operation{selectOper} + ret, err := self.ovsClient.Transact("Open_vSwitch", opers...) + if err != nil { + return "", fmt.Errorf("ovsdb select internal port mac transaction failed: %v", opers) + } + + if len(ret) == 0 || len(ret[0].Rows) == 0 { + return "", nil + } + + mac, ok := ret[0].Rows[0]["mac"].(string) + if !ok { + return "", nil + } + return mac, nil +} + func (self *OvsDriver) SetExternalIds(externalIds map[string]string) error { oMap := buildOVSDBMapFromMap(externalIds) row := make(map[string]interface{}) @@ -406,8 +430,8 @@ func (self *OvsDriver) UpdateInterface(ifaceName string, externalIDs map[string] // Create an internal port in OVS func (self *OvsDriver) CreatePort(intfName, intfType string, vlanTag uint) error { - portUuidStr := intfName - intfUuidStr := fmt.Sprintf("Intf%s", intfName) + portUuidStr := "portdummy" + intfUuidStr := "ifacedummy" portUuid := []libovsdb.UUID{{GoUuid: portUuidStr}} intfUuid := []libovsdb.UUID{{GoUuid: intfUuidStr}} opStr := "insert"