func updateDefaultGw(odb ovsdb.Ovsdb) { currMac, err := getMac("", quiltBridge) if err != nil { log.WithError(err).Errorf("failed to get MAC for %s", quiltBridge) return } if currMac != gatewayMAC { if err := odb.SetBridgeMac(quiltBridge, gatewayMAC); err != nil { log.WithError(err).Error("failed to set MAC for default gateway") } } if err := upLink("", quiltBridge); err != nil { log.WithError(err).Error("failed to up default gateway") } currIPs, err := listIP("", quiltBridge) if err != nil { log.WithError(err).Errorf("failed to list IPs") return } targetIPs := []string{gatewayIP + "/8"} if err := updateIPs("", quiltBridge, currIPs, targetIPs); err != nil { log.WithError(err).Errorf("failed to update IPs") } }
func addPort(odb ovsdb.Ovsdb, config ovsPort) error { if err := odb.CreateOFPort(config.bridge, config.name); err != nil { return fmt.Errorf("error creating openflow port: %s", err) } dummyPort := ovsPort{name: config.name, bridge: config.bridge} if err := modPort(odb, dummyPort, config); err != nil { return err } return nil }
func modPort(odb ovsdb.Ovsdb, current ovsPort, target ovsPort) error { if current.patch != target.patch && target.patch { err := odb.SetOFInterfaceType(target.name, ifaceTypePatch) if err != nil { return fmt.Errorf("error setting interface %s to type %s: %s", target.name, ifaceTypePatch, err) } } if current.peer != target.peer && target.peer != "" { err := odb.SetOFInterfacePeer(target.name, target.peer) if err != nil { return fmt.Errorf("error setting interface %s with peer %s: %s", target.name, target.peer, err) } } if current.attachedMAC != target.attachedMAC && target.attachedMAC != "" { err := odb.SetOFInterfaceAttachedMAC(target.name, target.attachedMAC) if err != nil { return fmt.Errorf("error setting interface %s with mac %s: %s", target.name, target.attachedMAC, err) } } if current.ifaceID != target.ifaceID && target.ifaceID != "" { err := odb.SetOFInterfaceIfaceID(target.name, target.ifaceID) if err != nil { return fmt.Errorf("error setting interface %s with id %s: %s", target.name, target.ifaceID, err) } } return nil }
// XXX This should actually be done at the level of the ovsdb wrapper. // As in, you should only have to get the row once, and then populate a // struct with all necessary fields and have them be picked out into here func populatePortConfig(odb ovsdb.Ovsdb, bridge, port string) ( *ovsPort, error) { config := &ovsPort{ name: port, bridge: bridge, } iface, err := odb.GetDefaultOFInterface(port) if err != nil { return nil, err } itype, err := odb.GetOFInterfaceType(iface) if err != nil && !ovsdb.IsExist(err) { return nil, err } else if err == nil { switch itype { case "patch": config.patch = true } } peer, err := odb.GetOFInterfacePeer(iface) if err != nil && !ovsdb.IsExist(err) { return nil, err } else if err == nil { config.peer = peer } attachedMAC, err := odb.GetOFInterfaceAttachedMAC(iface) if err != nil && !ovsdb.IsExist(err) { return nil, err } else if err == nil { config.attachedMAC = attachedMAC } ifaceID, err := odb.GetOFInterfaceIfaceID(iface) if err != nil && !ovsdb.IsExist(err) { return nil, err } else if err == nil { config.ifaceID = ifaceID } return config, nil }
func generateCurrentPorts(odb ovsdb.Ovsdb) (ovsPortSlice, error) { var configs ovsPortSlice for _, bridge := range []string{quiltBridge, ovnBridge} { ports, err := odb.ListOFPorts(bridge) if err != nil { return nil, fmt.Errorf("error listing ports on bridge %s: %s", bridge, err) } for _, port := range ports { cfg, err := populatePortConfig(odb, bridge, port) if err != nil { return nil, fmt.Errorf( "error populating port config: %s", err) } configs = append(configs, *cfg) } } return configs, nil }
// The target flows must be in the same format as the output from ovs-ofctl // dump-flows. To achieve this, we have some rather ugly hacks that handle // a few special cases. func generateTargetOpenFlow(dk docker.Client, odb ovsdb.Ovsdb, containers []db.Container, labels []db.Label, connections []db.Connection) (OFRuleSlice, error) { dflGatewayMAC, err := getMac("", quiltBridge) if err != nil { log.WithError(err).Error("failed to get MAC of default gateway.") } var rules []string for _, dbc := range containers { _, vethOut := veths(dbc.DockerID) _, peerQuilt := patchPorts(dbc.DockerID) dbcMac := dbc.Mac ofQuilt, err := odb.GetOFPortNo(peerQuilt) if err != nil { continue } ofVeth, err := odb.GetOFPortNo(vethOut) if err != nil { continue } if ofQuilt < 0 || ofVeth < 0 { continue } rules = append(rules, []string{ fmt.Sprintf("table=0 priority=%d,in_port=%d "+ "actions=output:%d", 5000, ofQuilt, ofVeth), fmt.Sprintf("table=2 priority=%d,in_port=%d "+ "actions=output:%d", 5000, ofVeth, ofQuilt), fmt.Sprintf("table=0 priority=%d,in_port=%d "+ "actions=output:%d", 0, ofVeth, ofQuilt), }...) protocols := []string{"tcp", "udp"} portsToWeb := make(map[int]struct{}) portsFromWeb := make(map[int]struct{}) for _, l := range dbc.Labels { for _, conn := range connections { if conn.From == l && conn.To == stitch.PublicInternetLabel { portsToWeb[conn.MinPort] = struct{}{} } else if conn.From == stitch.PublicInternetLabel && conn.To == l { portsFromWeb[conn.MinPort] = struct{}{} } } } // LOCAL is the default quilt-int port created with the bridge. egressRule := fmt.Sprintf("table=0 priority=%d,in_port=%d,", 5000, ofVeth) + "%s,%s," + fmt.Sprintf("dl_dst=%s actions=LOCAL", dflGatewayMAC) ingressRule := fmt.Sprintf("table=0 priority=%d,in_port=LOCAL,", 5000) + "%s,%s," + fmt.Sprintf("dl_dst=%s actions=%d", dbcMac, ofVeth) for port := range portsFromWeb { for _, protocol := range protocols { egressPort := fmt.Sprintf("tp_src=%d", port) rules = append(rules, fmt.Sprintf(egressRule, protocol, egressPort)) ingressPort := fmt.Sprintf("tp_dst=%d", port) rules = append(rules, fmt.Sprintf(ingressRule, protocol, ingressPort)) } } for port := range portsToWeb { for _, protocol := range protocols { egressPort := fmt.Sprintf("tp_dst=%d", port) rules = append(rules, fmt.Sprintf(egressRule, protocol, egressPort)) ingressPort := fmt.Sprintf("tp_src=%d", port) rules = append(rules, fmt.Sprintf(ingressRule, protocol, ingressPort)) } } var arpDst string if len(portsToWeb) > 0 || len(portsFromWeb) > 0 { // Allow ICMP rules = append(rules, fmt.Sprintf( "table=0 priority=%d,icmp,in_port=%d,dl_dst=%s"+ " actions=LOCAL", 5000, ofVeth, dflGatewayMAC)) rules = append(rules, fmt.Sprintf( "table=0 priority=%d,icmp,in_port=LOCAL,"+ "dl_dst=%s actions=output:%d", 5000, dbcMac, ofVeth)) arpDst = fmt.Sprintf("%d,LOCAL", ofQuilt) } else { arpDst = fmt.Sprintf("%d", ofQuilt) } if len(portsFromWeb) > 0 { // Allow default gateway to ARP for containers rules = append(rules, fmt.Sprintf( "table=0 priority=%d,arp,in_port=LOCAL,"+ "dl_dst=ff:ff:ff:ff:ff:ff actions=output:%d", 4500, ofVeth)) } rules = append(rules, fmt.Sprintf( "table=0 priority=%d,arp,in_port=%d "+ "actions=output:%s", 4500, ofVeth, arpDst)) rules = append(rules, fmt.Sprintf( "table=0 priority=%d,arp,in_port=LOCAL,"+ "dl_dst=%s actions=output:%d", 4500, dbcMac, ofVeth)) } LabelMacs := make(map[string]map[string]struct{}) for _, dbc := range containers { for _, l := range dbc.Labels { if _, ok := LabelMacs[l]; !ok { LabelMacs[l] = make(map[string]struct{}) } LabelMacs[l][dbc.Mac] = struct{}{} } } for _, label := range labels { if !label.MultiHost { continue } macs := LabelMacs[label.Label] if len(macs) == 0 { continue } ip := label.IP n := len(macs) lg2n := int(math.Ceil(math.Log2(float64(n)))) nxmRange := fmt.Sprintf("0..%d", lg2n) if lg2n == 0 { // dump-flows collapses 0..0 to just 0. nxmRange = "0" } mpa := fmt.Sprintf("multipath(symmetric_l3l4,0,modulo_n,%d,0,"+ "NXM_NX_REG0[%s])", n, nxmRange) rules = append(rules, fmt.Sprintf( "table=0 priority=%d,dl_dst=%s,ip,nw_dst=%s "+ "actions=%s,resubmit(,1)", 4000, labelMac, ip, mpa)) // We need the order to make diffing consistent. macList := make([]string, 0, n) for mac := range macs { macList = append(macList, mac) } sort.Strings(macList) i := 0 regPrefix := "" for _, mac := range macList { if i > 0 { // dump-flows puts a 0x prefix for all register values // except for 0. regPrefix = "0x" } reg0 := fmt.Sprintf("%s%x", regPrefix, i) rules = append(rules, fmt.Sprintf( "table=1 priority=5000,ip,nw_dst=%s,"+ "reg0=%s actions=mod_dl_dst:%s,resubmit(,2)", ip, reg0, mac)) i++ } } var targetRules OFRuleSlice for _, r := range rules { rule, err := makeOFRule(r) if err != nil { return nil, fmt.Errorf("failed to make OpenFlow rule: %s", err) } targetRules = append(targetRules, rule) } return targetRules, nil }
func delPort(odb ovsdb.Ovsdb, config ovsPort) error { if err := odb.DeleteOFPort(config.bridge, config.name); err != nil { return fmt.Errorf("error deleting openflow port: %s", err) } return nil }