Exemple #1
0
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")
	}
}
Exemple #2
0
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
}
Exemple #3
0
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
}
Exemple #4
0
// 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
}
Exemple #5
0
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
}
Exemple #6
0
// 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
}
Exemple #7
0
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
}