Beispiel #1
0
    def _flood_actions(
            self,
            in_port,
            external_ports,  # pylint: disable=too-many-arguments
            away_flood_actions,
            toward_flood_actions,
            local_flood_actions):
        if self.stack_manager.stack.is_root():
            if external_ports:
                flood_prefix = self._set_nonext_port_flag
            else:
                flood_prefix = self._set_ext_port_flag
            flood_actions = (away_flood_actions + local_flood_actions)

            if in_port and self.stack_manager.is_away(in_port):
                # Packet from a non-root switch, flood locally and to all non-root switches
                # (reflect it).
                flood_actions = (away_flood_actions +
                                 (valve_of.output_in_port(), ) +
                                 local_flood_actions)

            flood_actions = flood_prefix + flood_actions
        else:
            # Default non-root strategy is flood towards root.
            if external_ports:
                flood_actions = self._set_nonext_port_flag + toward_flood_actions
            else:
                flood_actions = self._set_ext_port_flag + toward_flood_actions

            if in_port:
                # Packet from switch further away, flood it to the root.
                if self.stack_manager.is_away(in_port):
                    flood_actions = toward_flood_actions
                # Packet from the root.
                elif self.stack_manager.is_towards_root(in_port):
                    # If we have external ports, and packet hasn't already been flooded
                    # externally, flood it externally before passing it to further away switches,
                    # and mark it flooded.
                    if external_ports:
                        flood_actions = (self._set_nonext_port_flag +
                                         away_flood_actions +
                                         local_flood_actions)
                    else:
                        flood_actions = (away_flood_actions +
                                         self._set_nonext_port_flag +
                                         local_flood_actions)
                # Packet from external port, locally. Mark it already flooded externally and
                # flood to root (it came from an external switch so keep it within the stack).
                elif in_port.loop_protect_external:
                    flood_actions = self._set_nonext_port_flag + toward_flood_actions
                else:
                    flood_actions = self._set_ext_port_flag + toward_flood_actions

        return flood_actions
Beispiel #2
0
    def _flood_actions(self, in_port, external_ports, away_flood_actions,
                       toward_flood_actions, local_flood_actions):
        # General case for stack with maximum distance > 2
        if self._dp_is_root():
            flood_actions = (self.ext_flood_needed + away_flood_actions +
                             local_flood_actions)

            if in_port:
                if in_port in self.away_from_root_stack_ports:
                    # Packet from a non-root switch, flood locally and to all non-root switches
                    # (reflect it).
                    flood_actions = (away_flood_actions +
                                     [valve_of.output_in_port()] +
                                     local_flood_actions)
                    # If we have external ports, let the non-roots know they don't have to
                    # flood externally.
                    if external_ports:
                        flood_actions = self.ext_flood_not_needed + flood_actions
                    else:
                        flood_actions = self.ext_flood_needed + flood_actions
                elif external_ports:
                    # Packet from an external switch, locally. As above, let the non-roots
                    # know they don't have to flood externally again.
                    flood_actions = (self.ext_flood_not_needed +
                                     away_flood_actions + local_flood_actions)

        else:
            # Default non-root strategy is flood towards root.
            flood_actions = self.ext_flood_needed + toward_flood_actions

            if in_port:
                # Packet from switch further away, flood it to the root.
                if in_port in self.away_from_root_stack_ports:
                    flood_actions = toward_flood_actions
                # Packet from the root.
                elif in_port in self.towards_root_stack_ports:
                    # If we have external ports, and packet hasn't already been flooded
                    # externally, flood it externally before passing it to further away switches,
                    # and mark it flooded.
                    if external_ports:
                        flood_actions = (self.ext_flood_not_needed +
                                         away_flood_actions +
                                         local_flood_actions)
                    else:
                        flood_actions = (away_flood_actions +
                                         self.ext_flood_not_needed +
                                         local_flood_actions)
                # Packet from external port, locally. Mark it already flooded externally and
                # flood to root (it came from an external switch so keep it within the stack).
                elif in_port.loop_protect_external:
                    flood_actions = self.ext_flood_not_needed + toward_flood_actions

        return flood_actions
Beispiel #3
0
    def _flood_actions(self, in_port, external_ports,
                       away_flood_actions, toward_flood_actions, local_flood_actions):
        # General case for stack with maximum distance > 2
        if self._dp_is_root():
            flood_actions = (
                self.ext_flood_needed + away_flood_actions + local_flood_actions)

            if in_port:
                if in_port in self.away_from_root_stack_ports:
                    # Packet from a non-root switch, flood locally and to all non-root switches
                    # (reflect it).
                    flood_actions = (
                        away_flood_actions + [valve_of.output_in_port()] + local_flood_actions)
                    # If we have external ports, let the non-roots know they don't have to
                    # flood externally.
                    if external_ports:
                        flood_actions = self.ext_flood_not_needed + flood_actions
                    else:
                        flood_actions = self.ext_flood_needed + flood_actions
                elif external_ports:
                    # Packet from an external switch, locally. As above, let the non-roots
                    # know they don't have to flood externally again.
                    flood_actions = (
                        self.ext_flood_not_needed + away_flood_actions + local_flood_actions)

        else:
            # Default non-root strategy is flood towards root.
            flood_actions = self.ext_flood_needed + toward_flood_actions

            if in_port:
                # Packet from switch further away, flood it to the root.
                if in_port in self.away_from_root_stack_ports:
                    flood_actions = toward_flood_actions
                # Packet from the root.
                elif in_port in self.towards_root_stack_ports:
                    # If we have external ports, and packet hasn't already been flooded
                    # externally, flood it externally before passing it to further away switches,
                    # and mark it flooded.
                    if external_ports:
                        flood_actions = (
                            self.ext_flood_not_needed + away_flood_actions + local_flood_actions)
                    else:
                        flood_actions = (
                            away_flood_actions + self.ext_flood_not_needed + local_flood_actions)
                # Packet from external port, locally. Mark it already flooded externally and
                # flood to root (it came from an external switch so keep it within the stack).
                elif in_port.loop_protect_external:
                    flood_actions = self.ext_flood_not_needed + toward_flood_actions

        return flood_actions
Beispiel #4
0
    def _build_flood_rule_actions(self, vlan, exclude_unicast, in_port):
        """Calculate flooding destinations based on this DP's position.

        If a standalone switch, then flood to local VLAN ports.

        If a distributed switch where all switches are directly
        connected to the root (star topology), edge switches flood locally
        and to the root, and the root floods to the other edges.

        If a non-star distributed switch topologies, use selective
        flooding (see the following example).

                               Hosts
                               ||||
                               ||||
                 +----+       +----+       +----+
              ---+1   |       |1234|       |   1+---
        Hosts ---+2   |       |    |       |   2+--- Hosts
              ---+3   |       |    |       |   3+---
              ---+4  5+-------+5  6+-------+5  4+---
                 +----+       +----+       +----+

                 Root DP

        Non-root switches flood only to the root. The root switch
        reflects incoming floods back out. Non-root switches
        flood packets from the root locally and further away.
        Flooding is entirely implemented in the dataplane.

        A host connected to a non-root switch can receive a copy
        of its own flooded packet (because the non-root switch
        does not know it has seen the packet already).

        A host connected to the root switch does not have this problem
        (because flooding is always away from the root). Therefore,
        connections to other non-FAUCET stacking networks should only
        be made to the root.

        On the root switch (left), flood destinations are:

        1: 2 3 4 5(s)
        2: 1 3 4 5(s)
        3: 1 2 4 5(s)
        4: 1 2 3 5(s)
        5: 1 2 3 4 5(s, note reflection)

        On the middle switch:

        1: 5(s)
        2: 5(s)
        3: 5(s)
        4: 5(s)
        5: 1 2 3 4 6(s)
        6: 5(s)

        On the rightmost switch:

        1: 5(s)
        2: 5(s)
        3: 5(s)
        4: 5(s)
        5: 1 2 3 4
        """
        exclude_ports = []
        dp_local_in_port = self._port_is_dp_local(in_port)
        if not dp_local_in_port:
            in_port_peer_dp = in_port.stack['dp']
            exclude_ports = [
                port for port in self.stack_ports
                if port.stack and port.stack['dp'] == in_port_peer_dp]
        local_flood_actions = self._build_flood_local_rule_actions(
            vlan, exclude_unicast, in_port)
        away_flood_actions = valve_of.flood_tagged_port_outputs(
            self.away_from_root_stack_ports, in_port, exclude_ports=exclude_ports)
        toward_flood_actions = valve_of.flood_tagged_port_outputs(
            self.towards_root_stack_ports, in_port)
        flood_all_except_self = away_flood_actions + local_flood_actions

        # TODO: optimization for 2 layer stack - no need to reflect off root.
        # We should generalize the edge switch case, too.
        if self.stack.get('longest_path_to_root_len', None) == 2:
            if self._dp_is_root():
                return away_flood_actions + local_flood_actions
            if dp_local_in_port:
                return toward_flood_actions + local_flood_actions
            return local_flood_actions

        if self._dp_is_root():
            if dp_local_in_port:
                return flood_all_except_self
            # If input port non-local, then flood outward again
            return [valve_of.output_in_port()] + flood_all_except_self

        # We are not the root of the distributed switch
        # If input port was connected to a switch closer to the root,
        # then flood outwards (local VLAN and stacks further than us)
        if in_port in self.towards_root_stack_ports:
            return flood_all_except_self
        # If input port local or from a further away switch, flood
        # towards the root.
        return toward_flood_actions
Beispiel #5
0
    def _build_flood_rule_actions(self, vlan, exclude_unicast, in_port):
        """Calculate flooding destinations based on this DP's position.

        If a standalone switch, then flood to local VLAN ports.

        If a distributed switch, see the following example.

                               Hosts
                               ||||
                               ||||
                 +----+       +----+       +----+
              ---+1   |       |1234|       |   1+---
        Hosts ---+2   |       |    |       |   2+--- Hosts
              ---+3   |       |    |       |   3+---
              ---+4  5+-------+5  6+-------+5  4+---
                 +----+       +----+       +----+

                 Root DP

        The basic strategy is flood-towards-root. The root
        reflects the flood back out. There are no loops and flooding
        is done entirely in the dataplane.

        On the root switch (left), flood destinations are:

        1: 2 3 4 5(s)
        2: 1 3 4 5(s)
        3: 1 2 4 5(s)
        4: 1 2 3 5(s)
        5: 1 2 3 4 5(s, note reflection)

        On the middle switch:

        1: 5(s)
        2: 5(s)
        3: 5(s)
        4: 5(s)
        5: 1 2 3 4 6(s)
        6: 5(s)

        On the rightmost switch:

        1: 5(s)
        2: 5(s)
        3: 5(s)
        4: 5(s)
        5: 1 2 3 4
        """
        local_flood_actions = self._build_flood_local_rule_actions(
            vlan, exclude_unicast, in_port)
        away_flood_actions = valve_of.flood_tagged_port_outputs(
            self.away_from_root_stack_ports, in_port)
        toward_flood_actions = valve_of.flood_tagged_port_outputs(
            self.towards_root_stack_ports, in_port)
        flood_all_except_self = away_flood_actions + local_flood_actions

        # If we're the root of a distributed switch..
        if self._dp_is_root():
            # If the input port was local, then flood local VLAN and stacks.
            if self._port_is_dp_local(in_port):
                return flood_all_except_self
            # If input port non-local, then flood outward again
            return [valve_of.output_in_port()] + flood_all_except_self

        # We are not the root of the distributed switch
        # If input port was connected to a switch closer to the root,
        # then flood outwards (local VLAN and stacks further than us)
        if in_port in self.towards_root_stack_ports:
            return flood_all_except_self
        # If input port local or from a further away switch, flood
        # towards the root.
        return toward_flood_actions
Beispiel #6
0
    def _build_flood_rule_actions(self, vlan, exclude_unicast, in_port):
        """Calculate flooding destinations based on this DP's position.

        If a standalone switch, then flood to local VLAN ports.

        If a distributed switch, use selective flooding
        (see the following example).

                               Hosts
                               ||||
                               ||||
                 +----+       +----+       +----+
              ---+1   |       |1234|       |   1+---
        Hosts ---+2   |       |    |       |   2+--- Hosts
              ---+3   |       |    |       |   3+---
              ---+4  5+-------+5  6+-------+5  4+---
                 +----+       +----+       +----+

                 Root DP

        Non-root switches flood only to the root. The root switch
        reflects incoming floods back out. Non-root switches
        flood packets from the root locally and further away.
        Flooding is entirely implemented in the dataplane.

        A host connected to a non-root switch can receive a copy
        of its own flooded packet (because the non-root switch
        does not know it has seen the packet already).

        A host connected to the root switch does not have this problem
        (because flooding is always away from the root). Therefore,
        connections to other non-FAUCET stacking networks should only
        be made to the root.

        On the root switch (left), flood destinations are:

        1: 2 3 4 5(s)
        2: 1 3 4 5(s)
        3: 1 2 4 5(s)
        4: 1 2 3 5(s)
        5: 1 2 3 4 5(s, note reflection)

        On the middle switch:

        1: 5(s)
        2: 5(s)
        3: 5(s)
        4: 5(s)
        5: 1 2 3 4 6(s)
        6: 5(s)

        On the rightmost switch:

        1: 5(s)
        2: 5(s)
        3: 5(s)
        4: 5(s)
        5: 1 2 3 4
        """
        local_flood_actions = self._build_flood_local_rule_actions(
            vlan, exclude_unicast, in_port)
        away_flood_actions = valve_of.flood_tagged_port_outputs(
            self.away_from_root_stack_ports, in_port)
        toward_flood_actions = valve_of.flood_tagged_port_outputs(
            self.towards_root_stack_ports, in_port)
        flood_all_except_self = away_flood_actions + local_flood_actions

        # If we're the root of a distributed switch..
        if self._dp_is_root():
            # If the input port was local, then flood local VLAN and stacks.
            if self._port_is_dp_local(in_port):
                return flood_all_except_self
            # If input port non-local, then flood outward again
            return [valve_of.output_in_port()] + flood_all_except_self

        # We are not the root of the distributed switch
        # If input port was connected to a switch closer to the root,
        # then flood outwards (local VLAN and stacks further than us)
        if in_port in self.towards_root_stack_ports:
            return flood_all_except_self
        # If input port local or from a further away switch, flood
        # towards the root.
        return toward_flood_actions
Beispiel #7
0
    def _build_flood_rule_actions(self, vlan, exclude_unicast, in_port):
        """Calculate flooding destinations based on this DP's position.

        If a standalone switch, then flood to local VLAN ports.

        If a distributed switch where all switches are directly
        connected to the root (star topology), edge switches flood locally
        and to the root, and the root floods to the other edges.

        If a non-star distributed switch topologies, use selective
        flooding (see the following example).

                               Hosts
                               ||||
                               ||||
                 +----+       +----+       +----+
              ---+1   |       |1234|       |   1+---
        Hosts ---+2   |       |    |       |   2+--- Hosts
              ---+3   |       |    |       |   3+---
              ---+4  5+-------+5  6+-------+5  4+---
                 +----+       +----+       +----+

                 Root DP

        Non-root switches flood only to the root. The root switch
        reflects incoming floods back out. Non-root switches
        flood packets from the root locally and further away.
        Flooding is entirely implemented in the dataplane.

        A host connected to a non-root switch can receive a copy
        of its own flooded packet (because the non-root switch
        does not know it has seen the packet already).

        A host connected to the root switch does not have this problem
        (because flooding is always away from the root). Therefore,
        connections to other non-FAUCET stacking networks should only
        be made to the root.

        On the root switch (left), flood destinations are:

        1: 2 3 4 5(s)
        2: 1 3 4 5(s)
        3: 1 2 4 5(s)
        4: 1 2 3 5(s)
        5: 1 2 3 4 5(s, note reflection)

        On the middle switch:

        1: 5(s)
        2: 5(s)
        3: 5(s)
        4: 5(s)
        5: 1 2 3 4 6(s)
        6: 5(s)

        On the rightmost switch:

        1: 5(s)
        2: 5(s)
        3: 5(s)
        4: 5(s)
        5: 1 2 3 4
        """
        exclude_ports = []
        dp_local_in_port = self._port_is_dp_local(in_port)
        if not dp_local_in_port:
            in_port_peer_dp = in_port.stack['dp']
            exclude_ports = [
                port for port in self.stack_ports
                if port.stack and port.stack['dp'] == in_port_peer_dp]
        local_flood_actions = self._build_flood_local_rule_actions(
            vlan, exclude_unicast, in_port)
        away_flood_actions = valve_of.flood_tagged_port_outputs(
            self.away_from_root_stack_ports, in_port, exclude_ports=exclude_ports)
        toward_flood_actions = valve_of.flood_tagged_port_outputs(
            self.towards_root_stack_ports, in_port)
        flood_all_except_self = away_flood_actions + local_flood_actions

        # TODO: optimization for 2 layer stack - no need to reflect off root.
        # We should generalize the edge switch case, too.
        if self.stack.get('longest_path_to_root_len', None) == 2:
            if self._dp_is_root():
                return away_flood_actions + local_flood_actions
            if dp_local_in_port:
                return toward_flood_actions + local_flood_actions
            return local_flood_actions

        if self._dp_is_root():
            if dp_local_in_port:
                return flood_all_except_self
            # If input port non-local, then flood outward again
            return [valve_of.output_in_port()] + flood_all_except_self

        # We are not the root of the distributed switch
        # If input port was connected to a switch closer to the root,
        # then flood outwards (local VLAN and stacks further than us)
        if in_port in self.towards_root_stack_ports:
            return flood_all_except_self
        # If input port local or from a further away switch, flood
        # towards the root.
        return toward_flood_actions