Пример #1
0
    def _configure_interface(self, mac_changed=True):
        """
        Applies sysctls and routes to the interface.

        :param: bool mac_changed: Has the MAC address changed since it was last
                     configured? If so, we reconfigure ARP for the interface in
                     IPv4 (ARP does not exist for IPv6, which uses neighbour
                     solicitation instead).
        """
        try:
            if self.ip_type == IPV4:
                devices.configure_interface_ipv4(self._iface_name)
                reset_arp = mac_changed
            else:
                ipv6_gw = self.endpoint.get("ipv6_gateway", None)
                devices.configure_interface_ipv6(self._iface_name, ipv6_gw)
                reset_arp = False

            ips = set()
            for ip in self.endpoint.get(self.nets_key, []):
                ips.add(futils.net_to_ip(ip))
            devices.set_routes(self.ip_type, ips, self._iface_name, self.endpoint["mac"], reset_arp=reset_arp)

        except (IOError, FailedSystemCall):
            if not devices.interface_exists(self._iface_name):
                _log.info("Interface %s for %s does not exist yet", self._iface_name, self.combined_id)
            elif not devices.interface_up(self._iface_name):
                _log.info("Interface %s for %s is not up yet", self._iface_name, self.combined_id)
            else:
                # Interface flapped back up after we failed?
                _log.warning("Failed to configure interface %s for %s", self._iface_name, self.combined_id)
Пример #2
0
    def test_configure_interface_ipv6_mainline(self):
        """
        Test that configure_interface_ipv6_mainline
            - opens and writes to the /proc system to enable proxy NDP on the
              interface.
            - calls ip -6 neigh to set up the proxy targets.

        Mainline test has two proxy targets.
        """
        m_open = mock.mock_open()
        rc = futils.CommandOutput("", "")
        if_name = "tap3e5a2b34222"
        proxy_target = "2001::3:4"

        open_patch = mock.patch('__builtin__.open', m_open, create=True)
        m_check_call = mock.patch('calico.felix.futils.check_call',
                                  return_value=rc)

        with nested(open_patch, m_check_call) as (_, m_check_call):
            devices.configure_interface_ipv6(if_name, proxy_target)
            calls = [mock.call('/proc/sys/net/ipv6/conf/%s/proxy_ndp' %
                               if_name,
                               'wb'),
                     M_ENTER,
                     mock.call().write('1'),
                     M_CLEAN_EXIT]
            m_open.assert_has_calls(calls)
            ip_calls = [mock.call(["ip", "-6", "neigh", "add", "proxy",
                                   str(proxy_target), "dev", if_name])]
            m_check_call.assert_has_calls(ip_calls)
Пример #3
0
    def _configure_interface(self):
        """
        Applies sysctls and routes to the interface.
        """
        try:
            if self.ip_type == IPV4:
                devices.configure_interface_ipv4(self._iface_name)
                nets_key = "ipv4_nets"
            else:
                ipv6_gw = self.endpoint.get("ipv6_gateway", None)
                devices.configure_interface_ipv6(self._iface_name, ipv6_gw)
                nets_key = "ipv6_nets"

            ips = set()
            for ip in self.endpoint.get(nets_key, []):
                ips.add(futils.net_to_ip(ip))
            devices.set_routes(self.ip_type, ips, self._iface_name,
                               self.endpoint["mac"])

        except (IOError, FailedSystemCall, CalledProcessError):
            if not devices.interface_exists(self._iface_name):
                _log.info("Interface %s for %s does not exist yet",
                          self._iface_name, self.endpoint_id)
            elif not devices.interface_up(self._iface_name):
                _log.info("Interface %s for %s is not up yet",
                          self._iface_name, self.endpoint_id)
            else:
                # OK, that really should not happen.
                _log.exception("Failed to configure interface %s for %s",
                               self._iface_name, self.endpoint_id)
                raise
Пример #4
0
    def test_configure_interface_ipv6_mainline(self):
        """
        Test that configure_interface_ipv6_mainline
            - opens and writes to the /proc system to enable proxy NDP on the
              interface.
            - calls ip -6 neigh to set up the proxy targets.

        Mainline test has two proxy targets.
        """
        m_open = mock.mock_open()
        rc = futils.CommandOutput("", "")
        if_name = "tap3e5a2b34222"
        proxy_target = "2001::3:4"

        open_patch = mock.patch('__builtin__.open', m_open, create=True)
        m_check_call = mock.patch('calico.felix.futils.check_call',
                                  return_value=rc)

        with nested(open_patch, m_check_call) as (_, m_check_call):
            devices.configure_interface_ipv6(if_name, proxy_target)
            calls = [mock.call('/proc/sys/net/ipv6/conf/%s/proxy_ndp' %
                               if_name,
                               'wb'),
                     M_ENTER,
                     mock.call().write('1'),
                     M_CLEAN_EXIT]
            m_open.assert_has_calls(calls)
            ip_calls = [mock.call(["ip", "-6", "neigh", "add", "proxy",
                                   str(proxy_target), "dev", if_name])]
            m_check_call.assert_has_calls(ip_calls)
Пример #5
0
    def _configure_interface(self):
        """
        Applies sysctls and routes to the interface.
        """
        try:
            if self.ip_type == IPV4:
                devices.configure_interface_ipv4(self._iface_name)
                nets_key = "ipv4_nets"
            else:
                ipv6_gw = self.endpoint.get("ipv6_gateway", None)
                devices.configure_interface_ipv6(self._iface_name, ipv6_gw)
                nets_key = "ipv6_nets"

            ips = set()
            for ip in self.endpoint.get(nets_key, []):
                ips.add(futils.net_to_ip(ip))
            devices.set_routes(self.ip_type, ips,
                               self._iface_name,
                               self.endpoint["mac"])

        except (IOError, FailedSystemCall, CalledProcessError):
            if not devices.interface_exists(self._iface_name):
                _log.info("Interface %s for %s does not exist yet",
                          self._iface_name, self.endpoint_id)
            elif not devices.interface_up(self._iface_name):
                _log.info("Interface %s for %s is not up yet",
                          self._iface_name, self.endpoint_id)
            else:
                # Interface flapped back up after we failed?
                _log.warning("Failed to configure interface %s for %s",
                             self._iface_name, self.endpoint_id)
Пример #6
0
    def _configure_interface(self):
        """
        Applies sysctls and routes to the interface.
        """
        if not self._device_is_up:
            _log.debug("Device is known to be down, skipping attempt to "
                       "configure it.")
            return
        try:
            if self.ip_type == IPV4:
                devices.configure_interface_ipv4(self._iface_name)
                reset_arp = self._mac_changed
            else:
                ipv6_gw = self.endpoint.get("ipv6_gateway", None)
                devices.configure_interface_ipv6(self._iface_name, ipv6_gw)
                reset_arp = False

            ips = set()
            for ip in self.endpoint.get(self.nets_key, []):
                ips.add(futils.net_to_ip(ip))
            for nat_map in self.endpoint.get(nat_key(self.ip_type), []):
                ips.add(nat_map['ext_ip'])
            devices.set_routes(self.ip_type,
                               ips,
                               self._iface_name,
                               self.endpoint.get("mac"),
                               reset_arp=reset_arp)

        except (IOError, FailedSystemCall) as e:
            if not devices.interface_exists(self._iface_name):
                _log.info("Interface %s for %s does not exist yet",
                          self._iface_name, self.combined_id)
            elif not devices.interface_up(self._iface_name):
                _log.info("Interface %s for %s is not up yet",
                          self._iface_name, self.combined_id)
            else:
                # Either the interface flapped back up after the failure (in
                # which case we'll retry when the event reaches us) or there
                # was a genuine failure due to bad data or some other factor.
                #
                # Since the former is fairly common, we log at warning level
                # rather than error, which avoids false positives.
                _log.warning(
                    "Failed to configure interface %s for %s: %r.  "
                    "Either the interface is flapping or it is "
                    "misconfigured.", self._iface_name, self.combined_id, e)
        else:
            _log.info("Interface %s configured", self._iface_name)
            super(WorkloadEndpoint, self)._configure_interface()
Пример #7
0
    def _configure_interface(self):
        """
        Applies sysctls and routes to the interface.
        """
        if not self._device_is_up:
            _log.debug("Device is known to be down, skipping attempt to "
                       "configure it.")
            return
        try:
            if self.ip_type == IPV4:
                devices.configure_interface_ipv4(self._iface_name)
                reset_arp = self._mac_changed
            else:
                ipv6_gw = self.endpoint.get("ipv6_gateway", None)
                devices.configure_interface_ipv6(self._iface_name, ipv6_gw)
                reset_arp = False

            ips = set()
            for ip in self.endpoint.get(self.nets_key, []):
                ips.add(futils.net_to_ip(ip))
            for nat_map in self.endpoint.get(nat_key(self.ip_type), []):
                ips.add(nat_map['ext_ip'])
            devices.set_routes(self.ip_type, ips,
                               self._iface_name,
                               self.endpoint["mac"],
                               reset_arp=reset_arp)

        except (IOError, FailedSystemCall) as e:
            if not devices.interface_exists(self._iface_name):
                _log.info("Interface %s for %s does not exist yet",
                          self._iface_name, self.combined_id)
            elif not devices.interface_up(self._iface_name):
                _log.info("Interface %s for %s is not up yet",
                          self._iface_name, self.combined_id)
            else:
                # Either the interface flapped back up after the failure (in
                # which case we'll retry when the event reaches us) or there
                # was a genuine failure due to bad data or some other factor.
                #
                # Since the former is fairly common, we log at warning level
                # rather than error, which avoids false positives.
                _log.warning("Failed to configure interface %s for %s: %r.  "
                             "Either the interface is flapping or it is "
                             "misconfigured.", self._iface_name,
                             self.combined_id, e)
        else:
            _log.info("Interface %s configured", self._iface_name)
            self._device_in_sync = True
Пример #8
0
    def _configure_interface(self):
        """
        Applies sysctls and routes to the interface.

        :param: bool mac_changed: Has the MAC address changed since it was last
                     configured? If so, we reconfigure ARP for the interface in
                     IPv4 (ARP does not exist for IPv6, which uses neighbour
                     solicitation instead).
        """
        try:
            if self.ip_type == IPV4:
                devices.configure_interface_ipv4(self._iface_name)
                reset_arp = self._mac_changed
            else:
                ipv6_gw = self.endpoint.get("ipv6_gateway", None)
                devices.configure_interface_ipv6(self._iface_name, ipv6_gw)
                reset_arp = False

            ips = set()
            for ip in self.endpoint.get(self.nets_key, []):
                ips.add(futils.net_to_ip(ip))
            devices.set_routes(self.ip_type,
                               ips,
                               self._iface_name,
                               self.endpoint["mac"],
                               reset_arp=reset_arp)

        except (IOError, FailedSystemCall):
            if not devices.interface_exists(self._iface_name):
                _log.info("Interface %s for %s does not exist yet",
                          self._iface_name, self.combined_id)
            elif not devices.interface_up(self._iface_name):
                _log.info("Interface %s for %s is not up yet",
                          self._iface_name, self.combined_id)
            else:
                # Interface flapped back up after we failed?
                _log.warning("Failed to configure interface %s for %s",
                             self._iface_name, self.combined_id)
        else:
            _log.info("Interface %s configured", self._iface_name)
            self._device_in_sync = True
            self._device_has_been_in_sync = True
Пример #9
0
    def program_endpoint(self, iptables_state):
        """
        Given an endpoint, make the programmed state match the desired state,
        setting up rules and creating chains and ipsets, but not putting
        content into the ipsets (leaving that for frules.update_acls).

        Note that if acl_data is none, we have not received any ACLs, and so
        we just leave the ACLs in place until we do. If there are none because
        this is a new endpoint, then we leave the endpoint with all routing
        disabled until we know better.

        The logic here is that we should create the routes and basic rules, but
        not the ACLs - leaving the ACLs as they were or with no access
        permitted if none. That is because we have the information for the
        former (routes and IP addresses for the endpoint) but not the latter
        (ACLs). However this split only makes sense at the point where the ACLs
        must have a default rule of "deny", so when issue39 is fully resolved
        this method should only be called when the ACLs are available too.

        Returns True if the endpoint needs to be retried (because the tap
        interface does not exist yet).
        """

        # Declare some utility functions
        def add_routes(routes, type):
            for route in routes:
                log.info("Add route to %s address %s for interface %s", type,
                         route, self.interface)
                devices.add_route(type, route, self.interface, self.mac)

        def remove_routes(routes, type):
            for route in routes:
                log.info(
                    "Remove extra %s route to address %s for interface %s",
                    type, route, self.interface)
                devices.del_route(type, route, self.interface)

        if not devices.interface_exists(self.interface):
            if self.state == Endpoint.STATE_ENABLED:
                log.error("Unable to configure non-existent interface %s",
                          self.interface)
                return True
            else:
                # No interface, but disabled. This is not an error, and there
                # is nothing to do.
                log.debug("Interface missing when disabling endpoint %s",
                          self.uuid)
                return False

        # If the interface is down, we can't configure it.
        if not devices.interface_up(self.interface):
            log.error("Unable to configure interface %s: interface is down.",
                      self.interface)
            return True

        # Configure the interface.
        if self.state == Endpoint.STATE_ENABLED:
            devices.configure_interface(self.interface)

            # List the IPv6 gateways to see if we need proxy NDP.
            ipv6_gateways = [
                addr.gateway for addr in self.addresses.values()
                if addr.version is 6
            ]
            if ipv6_gateways:
                devices.configure_interface_ipv6(self.interface, ipv6_gateways)

            # Build up list of addresses that should be present
            ipv4_intended = set([
                str(addr.ip) for addr in self.addresses.values()
                if addr.version is 4
            ])
            ipv6_intended = set([
                str(addr.ip) for addr in self.addresses.values()
                if addr.version is 6
            ])
        else:
            # Disabled endpoint; we should remove all the routes.
            ipv4_intended = set()
            ipv6_intended = set()

        ipv4_existing = devices.list_interface_ips(futils.IPV4, self.interface)
        ipv6_existing = devices.list_interface_ips(futils.IPV6, self.interface)

        # Determine the addresses that won't be changed.
        unchanged = ((ipv4_intended & ipv4_existing) |
                     (ipv6_intended & ipv6_existing))

        log.debug("Already got routes for %s for interface %s", unchanged,
                  self.interface)

        #*********************************************************************#
        #* Add and remove routes. Add any route we need but don't have, and  *#
        #* remove any route we have but don't need. These operations are     *#
        #* fast because they operate on sets.                                *#
        #*********************************************************************#
        add_routes(ipv4_intended - ipv4_existing, futils.IPV4)
        add_routes(ipv6_intended - ipv6_existing, futils.IPV6)
        remove_routes(ipv4_existing - ipv4_intended, futils.IPV4)
        remove_routes(ipv6_existing - ipv6_intended, futils.IPV6)

        #*********************************************************************#
        #* Set up the rules for this endpoint, not including ACLs. Note that *#
        #* if the endpoint is disabled, then it has no permitted addresses,  *#
        #* so it cannot send any data.                                       *#
        #*********************************************************************#
        frules.set_ep_specific_rules(iptables_state, self.suffix,
                                     self.interface, futils.IPV4,
                                     ipv4_intended, self.mac)
        frules.set_ep_specific_rules(iptables_state, self.suffix,
                                     self.interface, futils.IPV6,
                                     ipv6_intended, self.mac)

        #*********************************************************************#
        #* If we have just disabled / enabled an endpoint, we may need to    *#
        #* enable / disable incoming traffic. update_acls makes this         *#
        #* decision.                                                         *#
        #*********************************************************************#
        self.update_acls()

        return False