def provision_veth(self, namespace, veth_name_ns): """ Create the veth, move into the container namespace, add the IP and set up the default routes. Note, the endpoint will not be updated in etcd. If desired, the user should update the endpoint mac with the mac address provided by the function and then call update_endpoint :param self: The endpoint object to provision the veth on :param namespace: The namespace to operate in :type namespace netns.Namespace :param veth_name_ns: The name of the interface in the namespace :return The mac address of the veth as a string """ assert isinstance(namespace, netns.Namespace), \ 'Namespace object expected.' netns.create_veth(self.name, self.temp_interface_name) netns.move_veth_into_ns(namespace, self.temp_interface_name, veth_name_ns) for ip_net in self.ipv4_nets | self.ipv6_nets: netns.add_ip_to_ns_veth(namespace, ip_net.ip, veth_name_ns) netns.add_ns_default_route(namespace, self.name, veth_name_ns) return netns.get_ns_veth_mac(namespace, veth_name_ns)
def test_create_veth(self, m_check_output): """ Test creating a veth (pair). """ create_veth("veth1", "temp_name") check_output_1 = call( ["ip", "link", "add", "veth1", "type", "veth", "peer", "name", "temp_name"], timeout=IP_CMD_TIMEOUT ) check_output_2 = call(["ip", "link", "set", "veth1", "up"], timeout=IP_CMD_TIMEOUT) m_check_output.assert_has_calls([check_output_1, check_output_2])
def create_veth(endpoint): """ Create the veth, and configure the MAC address (since libnetwork does not do this). :param endpoint: The Endpoint being configured. """ # Create the veth pair. netns.create_veth(endpoint.name, endpoint.temp_interface_name) # Set the mac as libnetwork doesn't do this for us. netns.set_veth_mac(endpoint.temp_interface_name, endpoint.mac)
def test_create_veth(self, m_check_call): """ Test creating a veth (pair). """ create_veth("veth1", "temp_name") check_call_1 = call(['ip', 'link', 'add', "veth1", 'type', 'veth','peer', 'name', "temp_name"], timeout=IP_CMD_TIMEOUT) check_call_2 = call(['ip', 'link', 'set', "veth1", 'up'], timeout=IP_CMD_TIMEOUT) m_check_call.assert_has_calls([check_call_1, check_call_2])
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) network_id = json_data["NetworkID"] network_data = client.get_network(network_id) ipv4_gateway = "" if network_data and "IPv4Data" in network_data.keys(): ipv4_gateway = str(IPNetwork(network_data["IPv4Data"][0]["Gateway"]).ip) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e return_json = { "InterfaceName": {"SrcName": temp_interface_name, "DstPrefix": IF_PREFIX}, "Gateway": ipv4_gateway, # Leave gateway empty to trigger auto-gateway behaviour } app.logger.debug("Join Response JSON=%s", return_json) return jsonify(return_json)
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e return_json = { "InterfaceName": { "SrcName": temp_interface_name, "DstPrefix": IF_PREFIX }, "Gateway": "", # Leave gateway empty to trigger auto-gateway behaviour } app.logger.debug("Join Response JSON=%s", return_json) return jsonify(return_json)
def provision_veth(self, ns_pid, veth_name_ns): """ Create the veth, move into the container namespace, add the IP and set up the default routes. Note, the endpoint will not be updated in etcd. If desired, the user should update the endpoint mac with the mac address provided by the function and then call update_endpoint :param self: The endpoint object to provision the veth on :param ns_pid: The PID of the namespace to operate in :param veth_name_ns: The name of the interface in the namespace :return The mac address of the veth as a string """ netns.create_veth(self.name, self.temp_interface_name) netns.move_veth_into_ns(ns_pid, self.temp_interface_name, veth_name_ns) for ip_net in self.ipv4_nets | self.ipv6_nets: netns.add_ip_to_ns_veth(ns_pid, ip_net.ip, veth_name_ns) if ip_net.ip.version == 4: netns.add_ns_default_route(ns_pid, self.ipv4_gateway, veth_name_ns) else: netns.add_ns_default_route(ns_pid, self.ipv6_gateway, veth_name_ns) return netns.get_ns_veth_mac(ns_pid, veth_name_ns)
def container_add(container_id, ip, interface): """ Add a container (on this host) to Calico networking with the given IP. :param container_id: The namespace path or the docker name/ID of the container. :param ip: An IPAddress object with the desired IP to assign. :param interface: The name of the interface in the container. """ # The netns manipulations must be done as root. enforce_root() if container_id.startswith("/") and os.path.exists(container_id): # The ID is a path. Don't do any docker lookups workload_id = escape_etcd(container_id) orchestrator_id = NAMESPACE_ORCHESTRATOR_ID namespace = netns.Namespace(container_id) else: info = get_container_info_or_exit(container_id) workload_id = info["Id"] orchestrator_id = DOCKER_ORCHESTRATOR_ID namespace = netns.PidNamespace(info["State"]["Pid"]) # Check the container is actually running. if not info["State"]["Running"]: print "%s is not currently running." % container_id sys.exit(1) # We can't set up Calico if the container shares the host namespace. if info["HostConfig"]["NetworkMode"] == "host": print "Can't add %s to Calico because it is " \ "running NetworkMode = host." % container_id sys.exit(1) # Check if the container already exists try: _ = client.get_endpoint(hostname=hostname, orchestrator_id=orchestrator_id, workload_id=workload_id) except KeyError: # Calico doesn't know about this container. Continue. pass else: # Calico already set up networking for this container. Since we got # called with an IP address, we shouldn't just silently exit, since # that would confuse the user: the container would not be reachable on # that IP address. print "%s has already been configured with Calico Networking." % \ container_id sys.exit(1) # Check the IP is in the allocation pool. If it isn't, BIRD won't export # it. ip = IPAddress(ip) pool = get_pool_or_exit(ip) # The next hop IPs for this host are stored in etcd. next_hops = client.get_default_next_hops(hostname) try: next_hops[ip.version] except KeyError: print "This node is not configured for IPv%d." % ip.version sys.exit(1) # Assign the IP if not client.assign_address(pool, ip): print "IP address is already assigned in pool %s " % pool sys.exit(1) # Get the next hop for the IP address. next_hop = next_hops[ip.version] network = IPNetwork(IPAddress(ip)) ep = Endpoint(hostname=hostname, orchestrator_id=DOCKER_ORCHESTRATOR_ID, workload_id=workload_id, endpoint_id=uuid.uuid1().hex, state="active", mac=None) if network.version == 4: ep.ipv4_nets.add(network) ep.ipv4_gateway = next_hop else: ep.ipv6_nets.add(network) ep.ipv6_gateway = next_hop # Create the veth, move into the container namespace, add the IP and # set up the default routes. netns.create_veth(ep.name, ep.temp_interface_name) netns.move_veth_into_ns(namespace, ep.temp_interface_name, interface) netns.add_ip_to_ns_veth(namespace, ip, interface) netns.add_ns_default_route(namespace, next_hop, interface) # Grab the MAC assigned to the veth in the namespace. ep.mac = netns.get_ns_veth_mac(namespace, interface) # Register the endpoint with Felix. client.set_endpoint(ep) # Let the caller know what endpoint was created. return ep
def container_add(container_id, ip, interface): """ Add a container (on this host) to Calico networking with the given IP. :param container_id: The namespace path or the docker name/ID of the container. :param ip: An IPAddress object with the desired IP to assign. :param interface: The name of the interface in the container. """ # The netns manipulations must be done as root. enforce_root() # TODO: This section is redundant in container_add_ip and elsewhere if container_id.startswith("/") and os.path.exists(container_id): # The ID is a path. Don't do any docker lookups workload_id = escape_etcd(container_id) orchestrator_id = NAMESPACE_ORCHESTRATOR_ID namespace = netns.Namespace(container_id) else: info = get_container_info_or_exit(container_id) workload_id = info["Id"] orchestrator_id = DOCKER_ORCHESTRATOR_ID namespace = netns.PidNamespace(info["State"]["Pid"]) # Check the container is actually running. if not info["State"]["Running"]: print_paragraph("%s is not currently running." % container_id) sys.exit(1) # We can't set up Calico if the container shares the host namespace. if info["HostConfig"]["NetworkMode"] == "host": print_paragraph("Can't add %s to Calico because it is " "running NetworkMode = host." % container_id) sys.exit(1) # Check if the container already exists try: _ = client.get_endpoint(hostname=hostname, orchestrator_id=orchestrator_id, workload_id=workload_id) except KeyError: # Calico doesn't know about this container. Continue. pass else: # Calico already set up networking for this container. Since we got # called with an IP address, we shouldn't just silently exit, since # that would confuse the user: the container would not be reachable on # that IP address. print_paragraph("%s has already been configured with Calico " "Networking." % container_id) sys.exit(1) ep = Endpoint(hostname=hostname, orchestrator_id=DOCKER_ORCHESTRATOR_ID, workload_id=workload_id, endpoint_id=uuid.uuid1().hex, state="active", mac=None) ip, _ = get_ip_and_pool(ip) network = IPNetwork(ip) if network.version == 4: ep.ipv4_nets.add(network) else: ep.ipv6_nets.add(network) # Create the veth, move into the container namespace, add the IP and # set up the default routes. netns.increment_metrics(namespace) netns.create_veth(ep.name, ep.temp_interface_name) netns.move_veth_into_ns(namespace, ep.temp_interface_name, interface) netns.add_ip_to_ns_veth(namespace, ip, interface) netns.add_ns_default_route(namespace, ep.name, interface) # Grab the MAC assigned to the veth in the namespace. ep.mac = netns.get_ns_veth_mac(namespace, interface) # Register the endpoint with Felix. client.set_endpoint(ep) # Let the caller know what endpoint was created. print_paragraph("IP %s added to %s" % (str(ip), container_id)) return ep
def container_add(container_name, ip, interface): """ Add a container (on this host) to Calico networking with the given IP. :param container_name: The name or ID of the container. :param ip: An IPAddress object with the desired IP to assign. :param interface: The name of the interface in the container. """ # The netns manipulations must be done as root. enforce_root() info = get_container_info_or_exit(container_name) container_id = info["Id"] # Check if the container already exists try: _ = client.get_endpoint(hostname=hostname, orchestrator_id=ORCHESTRATOR_ID, workload_id=container_id) except KeyError: # Calico doesn't know about this container. Continue. pass else: # Calico already set up networking for this container. Since we got # called with an IP address, we shouldn't just silently exit, since # that would confuse the user: the container would not be reachable on # that IP address. print "%s has already been configured with Calico Networking." % \ container_name sys.exit(1) # Check the container is actually running. if not info["State"]["Running"]: print "%s is not currently running." % container_name sys.exit(1) # We can't set up Calico if the container shares the host namespace. if info["HostConfig"]["NetworkMode"] == "host": print "Can't add %s to Calico because it is " \ "running NetworkMode = host." % container_name sys.exit(1) # Check the IP is in the allocation pool. If it isn't, BIRD won't export # it. ip = IPAddress(ip) pool = get_pool_or_exit(ip) # The next hop IPs for this host are stored in etcd. next_hops = client.get_default_next_hops(hostname) try: next_hops[ip.version] except KeyError: print "This node is not configured for IPv%d." % ip.version sys.exit(1) # Assign the IP if not client.assign_address(pool, ip): print "IP address is already assigned in pool %s " % pool sys.exit(1) # Get the next hop for the IP address. next_hop = next_hops[ip.version] network = IPNetwork(IPAddress(ip)) ep = Endpoint(hostname=hostname, orchestrator_id=ORCHESTRATOR_ID, workload_id=container_id, endpoint_id=uuid.uuid1().hex, state="active", mac=None) if network.version == 4: ep.ipv4_nets.add(network) ep.ipv4_gateway = next_hop else: ep.ipv6_nets.add(network) ep.ipv6_gateway = next_hop # Create the veth, move into the container namespace, add the IP and # set up the default routes. pid = info["State"]["Pid"] netns.create_veth(ep.name, ep.temp_interface_name) netns.move_veth_into_ns(pid, ep.temp_interface_name, interface) netns.add_ip_to_ns_veth(pid, ip, interface) netns.add_ns_default_route(pid, next_hop, interface) # Grab the MAC assigned to the veth in the namespace. ep.mac = netns.get_ns_veth_mac(pid, interface) # Register the endpoint with Felix. client.set_endpoint(ep) # Let the caller know what endpoint was created. return ep
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) network_id = json_data["NetworkID"] endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e # Initialise our response data. json_response = { "InterfaceName": { "SrcName": temp_interface_name, "DstPrefix": IF_PREFIX, } } # Extract relevant data from the Network data. network_data = get_network_data(network_id) gateway_ip4, _ = get_gateway_pool_from_network_data(network_data, 4) gateway_ip6, _ = get_gateway_pool_from_network_data(network_data, 6) if (gateway_ip4 and is_using_calico_ipam(gateway_ip4)) or \ (gateway_ip6 and is_using_calico_ipam(gateway_ip6)): # One of the network gateway addresses indicate that we are using # Calico IPAM driver. In this case we setup routes using the gateways # configured on the endpoint (which will be our host IPs). app.logger.debug("Using Calico IPAM driver, configure gateway and " "static routes to the host") ep = client.get_endpoint(hostname=hostname, orchestrator_id=ORCHESTRATOR_ID, workload_id=CONTAINER_NAME, endpoint_id=endpoint_id) static_routes = [] if ep.ipv4_gateway: json_response["Gateway"] = str(ep.ipv4_gateway) static_routes.append({ "Destination": str(IPNetwork(ep.ipv4_gateway)), "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) if ep.ipv6_gateway: json_response["GatewayIPv6"] = str(ep.ipv6_gateway) static_routes.append({ "Destination": str(IPNetwork(ep.ipv6_gateway)), "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) json_response["StaticRoutes"] = static_routes else: # We are not using Calico IPAM driver, so configure blank gateways to # set up auto-gateway behavior. app.logger.debug("Not using Calico IPAM driver") json_response["Gateway"] = "" json_response["GatewayIPv6"] = "" app.logger.debug("Join Response JSON=%s", json_response) return jsonify(json_response)
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) network_id = json_data["NetworkID"] endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e # Initialise our response data. json_response = { "InterfaceName": { "SrcName": temp_interface_name, "DstPrefix": "eth", } } # Extract relevant data from the Network data. network_data = get_network_data(network_id) gateway_ip4, _ = get_gateway_pool_from_network_data(network_data, 4) gateway_ip6, _ = get_gateway_pool_from_network_data(network_data, 6) if (gateway_ip4 and is_using_calico_ipam(gateway_ip4)) or \ (gateway_ip6 and is_using_calico_ipam(gateway_ip6)): # One of the network gateway addresses indicate that we are using # Calico IPAM driver. In this case we setup routes using the gateways # configured on the endpoint (which will be our host IPs). app.logger.debug("Using Calico IPAM driver, configure gateway and " "static routes to the host") static_routes = [] if gateway_ip4: json_response["Gateway"] = DUMMY_IPV4_NEXTHOP static_routes.append({ "Destination": DUMMY_IPV4_NEXTHOP + "/32", "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) if gateway_ip6: # Here, we'll report the link local address of the host's cali interface to libnetwork # as our IPv6 gateway. IPv6 link local addresses are automatically assigned to interfaces # when they are brought up. Unfortunately, the container link must be up as well. So # bring it up now # TODO: create_veth should already bring up both links bring_up_interface(temp_interface_name) # Then extract the link local address that was just assigned to our host's interface next_hop_6 = get_next_hop_6(host_interface_name) json_response["GatewayIPv6"] = next_hop_6 static_routes.append({ "Destination": str(IPNetwork(next_hop_6)), "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) json_response["StaticRoutes"] = static_routes else: # We are not using Calico IPAM driver, so configure blank gateways to # set up auto-gateway behavior. app.logger.debug("Not using Calico IPAM driver") json_response["Gateway"] = "" json_response["GatewayIPv6"] = "" app.logger.debug("Join Response JSON=%s", json_response) return jsonify(json_response)
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) network_id = json_data["NetworkID"] endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e # Initialise our response data. json_response = { "InterfaceName": { "SrcName": temp_interface_name, "DstPrefix": IF_PREFIX, } } # Extract relevant data from the Network data. network_data = get_network_data(network_id) gateway_ip4, _ = get_gateway_pool_from_network_data(network_data, 4) gateway_ip6, _ = get_gateway_pool_from_network_data(network_data, 6) if (gateway_ip4 and is_using_calico_ipam(gateway_ip4)) or \ (gateway_ip6 and is_using_calico_ipam(gateway_ip6)): # One of the network gateway addresses indicate that we are using # Calico IPAM driver. In this case we setup routes using the gateways # configured on the endpoint (which will be our host IPs). app.logger.debug("Using Calico IPAM driver, configure gateway and " "static routes to the host") static_routes = [] if gateway_ip4: json_response["Gateway"] = DUMMY_IPV4_NEXTHOP static_routes.append({ "Destination": DUMMY_IPV4_NEXTHOP + "/32", "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) if gateway_ip6: # Here, we'll report the link local address of the host's cali interface to libnetwork # as our IPv6 gateway. IPv6 link local addresses are automatically assigned to interfaces # when they are brought up. Unfortunately, the container link must be up as well. So # bring it up now # TODO: create_veth should already bring up both links bring_up_interface(temp_interface_name) # Then extract the link local address that was just assigned to our host's interface next_hop_6 = get_ipv6_link_local(host_interface_name) json_response["GatewayIPv6"] = next_hop_6 static_routes.append({ "Destination": str(IPNetwork(next_hop_6)), "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) json_response["StaticRoutes"] = static_routes else: # We are not using Calico IPAM driver, so configure blank gateways to # set up auto-gateway behavior. app.logger.debug("Not using Calico IPAM driver") json_response["Gateway"] = "" json_response["GatewayIPv6"] = "" app.logger.debug("Join Response JSON=%s", json_response) return jsonify(json_response)
def container_add(container_id, ip, interface): """ Add a container (on this host) to Calico networking with the given IP. :param container_id: The namespace path or the docker name/ID of the container. :param ip: An IPAddress object with the desired IP to assign. :param interface: The name of the interface in the container. """ # The netns manipulations must be done as root. enforce_root() # TODO: This section is redundant in container_add_ip and elsewhere if container_id.startswith("/") and os.path.exists(container_id): # The ID is a path. Don't do any docker lookups workload_id = escape_etcd(container_id) orchestrator_id = NAMESPACE_ORCHESTRATOR_ID namespace = netns.Namespace(container_id) else: info = get_container_info_or_exit(container_id) workload_id = info["Id"] orchestrator_id = DOCKER_ORCHESTRATOR_ID namespace = netns.PidNamespace(info["State"]["Pid"]) # Check the container is actually running. if not info["State"]["Running"]: print_paragraph("%s is not currently running." % container_id) sys.exit(1) # We can't set up Calico if the container shares the host namespace. if info["HostConfig"]["NetworkMode"] == "host": print_paragraph("Can't add %s to Calico because it is " "running NetworkMode = host." % container_id) sys.exit(1) # Check if the container already exists try: _ = client.get_endpoint(hostname=hostname, orchestrator_id=orchestrator_id, workload_id=workload_id) except KeyError: # Calico doesn't know about this container. Continue. pass else: # Calico already set up networking for this container. Since we got # called with an IP address, we shouldn't just silently exit, since # that would confuse the user: the container would not be reachable on # that IP address. print_paragraph("%s has already been configured with Calico " "Networking." % container_id) sys.exit(1) ip, pool = get_ip_and_pool(ip) try: # The next hop IPs for this host are stored in etcd. next_hops = client.get_default_next_hops(hostname) next_hops[ip.version] except KeyError: print_paragraph("This node is not configured for IPv%d. " "Is calico-node running?" % ip.version) unallocated_ips = client.release_ips({ip}) if unallocated_ips: print_paragraph("Error during cleanup. %s was already" "unallocated." % ip) sys.exit(1) # Get the next hop for the IP address. next_hop = next_hops[ip.version] network = IPNetwork(IPAddress(ip)) ep = Endpoint(hostname=hostname, orchestrator_id=DOCKER_ORCHESTRATOR_ID, workload_id=workload_id, endpoint_id=uuid.uuid1().hex, state="active", mac=None) if network.version == 4: ep.ipv4_nets.add(network) ep.ipv4_gateway = next_hop else: ep.ipv6_nets.add(network) ep.ipv6_gateway = next_hop # Create the veth, move into the container namespace, add the IP and # set up the default routes. netns.increment_metrics(namespace) netns.create_veth(ep.name, ep.temp_interface_name) netns.move_veth_into_ns(namespace, ep.temp_interface_name, interface) netns.add_ip_to_ns_veth(namespace, ip, interface) netns.add_ns_default_route(namespace, next_hop, interface) # Grab the MAC assigned to the veth in the namespace. ep.mac = netns.get_ns_veth_mac(namespace, interface) # Register the endpoint with Felix. client.set_endpoint(ep) # Let the caller know what endpoint was created. print_paragraph("IP %s added to %s" % (str(ip), container_id)) return ep