示例#1
0
 def _build_flood_rule_actions(
         self,
         vlan,
         exclude_unicast,
         in_port,  # pylint: disable=too-many-arguments
         exclude_all_external=False,
         exclude_restricted_bcast_arpnd=False):
     """Compiles all the possible flood rule actions for a port on a stack node"""
     exclude_ports = list(self.stack_manager.inactive_away_ports)
     external_ports = vlan.loop_protect_external_ports()
     if in_port and self.stack_manager.is_stack_port(in_port):
         in_port_peer_dp = in_port.stack['dp']
         exclude_ports = exclude_ports + self.stack_manager.adjacent_stack_ports(
             in_port_peer_dp)
     local_flood_actions = tuple(
         self._build_flood_local_rule_actions(
             vlan, exclude_unicast, in_port, exclude_all_external,
             exclude_restricted_bcast_arpnd))
     away_flood_actions = tuple(
         valve_of.flood_tagged_port_outputs(self.stack_manager.away_ports,
                                            in_port,
                                            exclude_ports=exclude_ports))
     toward_flood_actions = tuple(
         valve_of.flood_tagged_port_outputs(
             self.stack_manager.chosen_towards_ports, in_port))
     flood_acts = self._flood_actions(in_port, external_ports,
                                      away_flood_actions,
                                      toward_flood_actions,
                                      local_flood_actions)
     return flood_acts
示例#2
0
    def _build_flood_rule_actions(self,
                                  vlan,
                                  exclude_unicast,
                                  in_port,
                                  exclude_all_external=False,
                                  exclude_restricted_bcast_arpnd=False):
        exclude_ports = self._inactive_away_stack_ports()
        external_ports = vlan.loop_protect_external_ports()

        if in_port and in_port in self.stack_ports:
            in_port_peer_dp = in_port.stack['dp']
            exclude_ports = exclude_ports + [
                port for port in self.stack_ports
                if port.stack['dp'] == in_port_peer_dp
            ]
        local_flood_actions = self._build_flood_local_rule_actions(
            vlan, exclude_unicast, in_port, exclude_all_external,
            exclude_restricted_bcast_arpnd)
        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_acts = self._flood_actions(in_port, external_ports,
                                         away_flood_actions,
                                         toward_flood_actions,
                                         local_flood_actions)
        return flood_acts
示例#3
0
 def _build_flood_local_rule_actions(vlan, exclude_unicast, in_port):
     """Return a list of flood actions to flood packets from a port."""
     flood_acts = []
     tagged_ports = vlan.tagged_flood_ports(exclude_unicast)
     flood_acts.extend(
         valve_of.flood_tagged_port_outputs(tagged_ports, in_port))
     untagged_ports = vlan.untagged_flood_ports(exclude_unicast)
     flood_acts.extend(
         valve_of.flood_untagged_port_outputs(untagged_ports, in_port))
     return flood_acts
示例#4
0
 def _build_flood_local_rule_actions(vlan, exclude_unicast, in_port):
     """Return a list of flood actions to flood packets from a port."""
     flood_acts = []
     exclude_ports = []
     if in_port is not None and in_port.lacp:
         lags = vlan.lags()
         exclude_ports = lags[in_port.lacp]
     tagged_ports = vlan.tagged_flood_ports(exclude_unicast)
     flood_acts.extend(valve_of.flood_tagged_port_outputs(
         tagged_ports, in_port=in_port, exclude_ports=exclude_ports))
     untagged_ports = vlan.untagged_flood_ports(exclude_unicast)
     flood_acts.extend(valve_of.flood_untagged_port_outputs(
         untagged_ports, in_port=in_port, exclude_ports=exclude_ports))
     return flood_acts
示例#5
0
 def _build_flood_local_rule_actions(vlan, exclude_unicast, in_port):
     """Return a list of flood actions to flood packets from a port."""
     flood_acts = []
     exclude_ports = set()
     lags = vlan.lags()
     if lags:
         if in_port is not None and in_port.lacp:
             # Don't flood from one LACP bundle member, to another.
             exclude_ports.update(lags[in_port.lacp])
         # Pick one up bundle member to flood to.
         for ports in list(lags.values()):
             exclude_ports.update(ports[1:])
     tagged_ports = vlan.tagged_flood_ports(exclude_unicast)
     flood_acts.extend(valve_of.flood_tagged_port_outputs(
         tagged_ports, in_port=in_port, exclude_ports=exclude_ports))
     untagged_ports = vlan.untagged_flood_ports(exclude_unicast)
     flood_acts.extend(valve_of.flood_untagged_port_outputs(
         untagged_ports, in_port=in_port, exclude_ports=exclude_ports))
     return flood_acts
示例#6
0
    def _build_flood_rule_actions(self,
                                  vlan,
                                  exclude_unicast,
                                  in_port,
                                  exclude_all_external=False):
        """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 = []
        external_ports = vlan.loop_protect_external_ports_up()

        if in_port and in_port in self.stack_ports:
            in_port_peer_dp = in_port.stack['dp']
            exclude_ports = [
                port for port in self.stack_ports
                if port.stack['dp'] == in_port_peer_dp
            ]
        local_flood_actions = self._build_flood_local_rule_actions(
            vlan, exclude_unicast, in_port, exclude_all_external)
        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)

        if self.stack_size == 2:
            flood_acts = self._flood_actions_size2(in_port, external_ports,
                                                   away_flood_actions,
                                                   toward_flood_actions,
                                                   local_flood_actions)
        else:
            flood_acts = self._flood_actions(in_port, external_ports,
                                             away_flood_actions,
                                             toward_flood_actions,
                                             local_flood_actions)
        return valve_of.dedupe_ofmsgs(flood_acts)
示例#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
示例#8
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
示例#9
0
    def _build_flood_rule_actions(self, vlan, exclude_unicast, in_port, exclude_all_external=False):
        """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 = []
        external_ports = vlan.loop_protect_external_ports_up()

        if in_port and in_port in self.stack_ports:
            in_port_peer_dp = in_port.stack['dp']
            exclude_ports = [
                port for port in self.stack_ports
                if port.stack['dp'] == in_port_peer_dp]
        local_flood_actions = self._build_flood_local_rule_actions(
            vlan, exclude_unicast, in_port, exclude_all_external)
        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_acts = self._flood_actions_func(
            in_port, external_ports, away_flood_actions,
            toward_flood_actions, local_flood_actions)
        return flood_acts
示例#10
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
示例#11
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