def activate_interface(self, interface): """ moves the interface to the CNI netnt, rename it, set the IP address, and the GW. """ _, netns = os.path.split(self.netns) iproute_ns = NetNS(netns) veth_index = get_iface_index(interface.veth.name, self.iproute) actived_idxs = iproute_ns.link_lookup(operstate="UP") if (veth_index in actived_idxs): return logger.info("Move interface {}/{} to netns {}".format( interface.veth.name, veth_index, netns)) self.iproute.link('set', index=veth_index, net_ns_fd=netns) # configure and activate interfaces inside the netns iproute_ns.link('set', index=veth_index, ifname=self.interface) lo_idx = iproute_ns.link_lookup(ifname="lo")[0] iproute_ns.link('set', index=lo_idx, state='up') iproute_ns.link('set', index=veth_index, state='up') iproute_ns.addr('add', index=veth_index, address=interface.address.ip_address, prefixlen=int(interface.address.ip_prefix)) iproute_ns.route('add', gateway=interface.address.gateway_ip) # Disable TSO and checksum offload as xdp currently does not support logger.info("Disable tso for pod") cmd = "ip netns exec {} ethtool -K {} tso off gso off ufo off".format( netns, "eth0") rc, text = run_cmd(cmd) logger.info("Executed cmd {} tso rc: {} text {}".format(cmd, rc, text)) logger.info("Disable rx tx offload for pod") cmd = "ip netns exec {} ethtool --offload {} rx off tx off".format( netns, "eth0") rc, text = run_cmd(cmd) logger.info("Executed cmd {} rc: {} text {}".format(cmd, rc, text))
def connect_nodes_to_switch(self): """ This will create veth pairs for all links definid in the network config. Each veth will also be moved to the correct network namespace. """ client_low = docker.APIClient() self.start_containers() ip = IPRoute() # Check if netns folder exists. If not, create one for netns to look intp if not os.path.exists("/var/run/netns"): os.mkdir("/var/run/netns") for link in self.network_config["links"]: device1 = link["device1"] device2 = link["device2"] pid_device1 = client_low.inspect_container(device1)["State"]["Pid"] pid_device2 = client_low.inspect_container(device2)["State"]["Pid"] # Interface names. Naming convention will be different dempending on connection type iface_device1 = "" iface_device2 = "" # If connectiong to switch. Make sure it is setup if link["type"] == "Node_to_Switch": switch_is_setup = os.path.exists(f"/proc/{pid_device2}/ns/net") # Wait until switch is setup max_wait_seconds = 10 seconds_waited = 0 while not switch_is_setup and seconds_waited <= max_wait_seconds: switch_is_setup = os.path.exists(f"/proc/{pid_device2}/ns/net") time.sleep(1) seconds_waited += 1 # Check if namespaces are addad. If not add simlinuk to namespace if not os.path.islink(f"/var/run/netns/{device1}"): os.symlink( f"/proc/{pid_device1}/ns/net", f"/var/run/netns/{device1}", ) if not os.path.islink(f"/var/run/netns/{device2}"): if not os.path.exists(f"/var/run/netns/{device2}"): os.symlink( f"/proc/{pid_device2}/ns/net", f"/var/run/netns/{device2}", ) iface_device1 = f"{link['device1']}_{link['device1_port']}" iface_device2 = f"{link['device2']}_{link['device2_port']}" # Create Veth pair and put them in the right namespace ip.link("add", ifname=iface_device1, peer=iface_device2, kind="veth") id_node = ip.link_lookup(ifname=iface_device1)[0] ip.link("set", index=id_node, state="up") ip.link("set", index=id_node, net_ns_fd=link["device1"]) id_switch = ip.link_lookup(ifname=iface_device2)[0] ip.link("set", index=id_switch, state="up") ip.link("set", index=id_switch, net_ns_fd=link["device2"]) # Start all veth port in Nodes ns = NetNS(device1) ns.link("set", index=id_node, state="up") if "ipv4_addr" in self.network_config["nodes"][device1]: ns.addr( "add", index=id_node, address=self.network_config["nodes"][device1]["ipv4_addr"], prefixlen=24, ) if "ipv6_addr" in link: continue if link["type"] == "Switch_to_Switch": switch_is_setup1 = os.path.exists(f"/proc/{pid_device1}/ns/net") switch_is_setup2 = os.path.exists(f"/proc/{pid_device2}/ns/net") max_wait_seconds = 10 seconds_waited = 0 while not switch_is_setup1 and switch_is_setup2: switch_is_setup1 = os.path.exists(f"/proc/{pid_device1}/ns/net") switch_is_setup2 = os.path.exists(f"/proc/{pid_device2}/ns/net") time.sleep(1) seconds_waited += 1 # Check if namespaces are addad. If not add simlink to namespace if not os.path.islink(f"/var/run/netns/{device1}"): os.symlink( f"/proc/{pid_device1}/ns/net", f"/var/run/netns/{device1}", ) if not os.path.islink(f"/var/run/netns/{device2}"): if not os.path.exists(f"/var/run/netns/{device2}"): os.symlink( f"/proc/{pid_device2}/ns/net", f"/var/run/netns/{device2}", ) iface_switch1 = f"{link['device1']}_{link['device1_port']}" iface_switch2 = f"{link['device2']}_{link['device2_port']}" # Create Veth pair and put them in the right namespace ip.link("add", ifname=iface_switch1, peer=iface_switch2, kind="veth") id_switch1 = ip.link_lookup(ifname=iface_switch1)[0] ip.link("set", index=id_switch1, state="up") ip.link("set", index=id_switch1, net_ns_fd=link["device1"]) id_switch2 = ip.link_lookup(ifname=iface_switch2)[0] ip.link("set", index=id_switch2, state="up") ip.link("set", index=id_switch2, net_ns_fd=link["device2"]) # Start all veth in all the switches for switch in self.switches: ns = NetNS(switch.name) net_interfaces = ns.get_links() for interface in net_interfaces[2:]: iface_name = interface["attrs"][0][1] id_switch = ns.link_lookup(ifname=iface_name)[0] ns.link("set", index=id_switch, state="up")