--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from nepi.core.decription import AF_INET
+from nepi.testbeds import netns
+
+instance = netns.TestbedInstance(None)
+
+instance.create(2, "Node", [])
+instance.create(3, "Node", [])
+instance.create(4, "NodeInterface", [])
+instance.create_set(4, "up", True)
+instance.connect(2, "devs", 4, "node")
+instance.add_adddress(4, AF_INET, "10.0.0.1", None, None)
+instance.create(5, "NodeInterface", [])
+instance.create_set(5, "up", True)
+instance.connect(3, "devs", 5, "node")
+instance.add_adddress(5, AF_INET, "10.0.0.2", None, None)
+instance.create(6, "Switch", [])
+instance.create_set(6, "up", True)
+instance.connect(4, "switch", 6, "devs")
+instance.connect(5, "switch", 6, "devs")
+instance.create(7, "Application", [])
+instance.create_set(7, "command", "ping -qc10 10.0.0.2")
+instance.connect(7, "node", 2, "apps")
+
+instance.do_create()
+instance.do_connect()
+instance.do_configure()
+instance.start()
+import time
+time.sleep(5)
+instance.stop()
+
return self._attributes[name].type
def get_attribute_range(self, name):
+ if not self._attributes[name].range:
+ return (None, None)
return self._attributes[name].range
def get_attribute_allowed(self, name):
def destroy(self):
for testbed_description in self.testbed_descriptions:
testbed_description.destroy()
+
def __init__(self, configuration):
pass
- def create(self, guid, factory_id, parameters):
+ def create(self, guid, factory_id):
+ """Instructs creation of element """
+ raise NotImplementedError
+
+ def create_set(self, guid, name, value):
+ """Instructs setting an attribute on an element"""
raise NotImplementedError
def do_create(self):
+ """After do_create all instructed elements are created and
+ attributes setted"""
raise NotImplementedError
- def connect(self, object1_guid, object2_guid, connect_code):
+ def connect(self, guid1, connector_type_name1, guid2,
+ connector_type_name2):
raise NotImplementedError
def do_connect(self):
raise NotImplementedError
- def enable_trace(self, guid, trace_id):
+ def add_trace(self, guid, trace_id):
raise NotImplementedError
- def add_adddress(self, guid):
- #TODO
+ def add_adddress(self, guid, family, address, netprefix, broadcast):
raise NotImplementedError
- def add_route(self, guid):
- #TODO
+ def add_route(self, guid, family, destination, netprefix, nexthop,
+ interface):
raise NotImplementedError
def do_configure(self):
raise NotImplementedError
- def cross_connect(self, guid, connect_code, paremeters):
- raise NotImplementedError
-
def do_cross_connect(self):
raise NotImplementedError
def start(self, time):
raise NotImplementedError
+ def action(self, time, guid, action):
+ raise NotImplementedError
+
def stop(self, time):
raise NotImplementedError
def status(self, guid):
raise NotImplementedError
- def get_trace(self, time, guid, trace_id):
+ def trace(self, guid, trace_id):
raise NotImplementedError
def shutdown(self):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-from nepi.core import description
-import sys
-
-TESTBED_ID = "netns"
-
-def add_connector_types(factory, connector_types_metadata):
- for (connector_type_id, help, name, max, min,
- allowed_connector_type_ids) in connector_types_metadata:
- factory.add_connector_type(connector_type_id, help, name, max,
- min, allowed_connector_type_ids)
-
-def add_traces(factory, traces_metadata):
- for (name, help) in traces_metadata:
- factory.add_trace(name, help)
-
-def add_attributes(factory, attributes_metadata):
- for (name, help, type, value, range, allowed, readonly,
- validation_function) in attributes_metadata:
- factory.add_attribute(name, help, type, value, range, allowed,
- readonly, validation_function)
-
-def add_box_attributes(factory, box_attributes_metadata):
- for (name, help, type, value, range, allowed, readonly,
- validation_function) in box_attributes_metadata:
- factory.add_box_attribute(name, help, type, value, range,
- allowed, readonly, validation_function)
-
-def create_factory_from_metadata(factory_id, info):
- help = info["help"]
- category = info["category"]
- display_name = info["display_name"]
- factory_type = info["factory_type"] if "factory_type" in info else None
- if factory_type == "addressable":
- family = info["family"]
- max_addresses = info["max_addresses"]
- factory = description.AddressableBoxFactory(factory_id,
- display_name, family, max_addresses, help, category)
- elif factory_type == "routing":
- factory = description.RoutingTableBoxFactory(factory_id,
- display_name, help, category)
- else:
- factory = description.BoxFactory(factory_id, display_name, help, category)
- if "connector_types" in info:
- add_connector_types(factory, info["connector_types"])
- if "traces" in info:
- add_traces(factory, info["traces"])
- if "attributes" in info:
- add_attributes(factory, info["attributes"])
- if "box_attributes" in info:
- add_box_attributes(factory, info["box_attributes"])
- return factory
-
-def create_factories(version):
- factories = list()
- mod_name = "%s.metadata_v%s" % (__name__, version)
- if not mod_name in sys.modules:
- __import__(mod_name)
- metadata = sys.modules[mod_name].get_metadata()
- for factory_id, info in metadata.iteritems():
- factory = create_factory_from_metadata(factory_id, info)
- factories.append(factory)
- return factories
-
-class TestbedFactoriesProvider(description.TestbedFactoriesProvider):
- def __init__(self, testbed_version):
- super(TestbedFactoriesProvider, self).__init__(TESTBED_ID,
- testbed_version)
- for factory in create_factories(testbed_version):
- self.add_factory(factory)
-
+from description import TestbedFactoriesProvider
+from testbed import TestbedInstance
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from nepi.core import description
+import sys
+
+TESTBED_ID = "netns"
+
+def add_connector_types(factory, connector_types_metadata):
+ for (connector_type_id, help, name, max, min,
+ allowed_connector_type_ids) in connector_types_metadata:
+ factory.add_connector_type(connector_type_id, help, name, max,
+ min, allowed_connector_type_ids)
+
+def add_traces(factory, traces_metadata):
+ for (name, help) in traces_metadata:
+ factory.add_trace(name, help)
+
+def add_attributes(factory, attributes_metadata):
+ for (name, help, type, value, range, allowed, readonly,
+ validation_function) in attributes_metadata:
+ factory.add_attribute(name, help, type, value, range, allowed,
+ readonly, validation_function)
+
+def add_box_attributes(factory, box_attributes_metadata):
+ for (name, help, type, value, range, allowed, readonly,
+ validation_function) in box_attributes_metadata:
+ factory.add_box_attribute(name, help, type, value, range,
+ allowed, readonly, validation_function)
+
+def create_factory_from_metadata(factory_id, info):
+ help = info["help"]
+ category = info["category"]
+ display_name = info["display_name"]
+ factory_type = info["factory_type"] if "factory_type" in info else None
+ if factory_type == "addressable":
+ family = info["family"]
+ max_addresses = info["max_addresses"]
+ factory = description.AddressableBoxFactory(factory_id,
+ display_name, family, max_addresses, help, category)
+ elif factory_type == "routing":
+ factory = description.RoutingTableBoxFactory(factory_id,
+ display_name, help, category)
+ else:
+ factory = description.BoxFactory(factory_id, display_name, help, category)
+ if "connector_types" in info:
+ add_connector_types(factory, info["connector_types"])
+ if "traces" in info:
+ add_traces(factory, info["traces"])
+ if "attributes" in info:
+ add_attributes(factory, info["attributes"])
+ if "box_attributes" in info:
+ add_box_attributes(factory, info["box_attributes"])
+ return factory
+
+def create_factories(version):
+ factories = list()
+ mod_name = "nepi.testbeds.netns.metadata_v%s" % (version)
+ if not mod_name in sys.modules:
+ __import__(mod_name)
+ metadata = sys.modules[mod_name].get_metadata()
+ for factory_id, info in metadata.iteritems():
+ factory = create_factory_from_metadata(factory_id, info)
+ factories.append(factory)
+ return factories
+
+class TestbedFactoriesProvider(description.TestbedFactoriesProvider):
+ def __init__(self, testbed_version):
+ super(TestbedFactoriesProvider, self).__init__(TESTBED_ID,
+ testbed_version)
+ for factory in create_factories(testbed_version):
+ self.add_factory(factory)
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from nepi.core import testbed
+
+CREATE = 0
+SET = 1
+CONNECT = 2
+ADD_TRACE = 3
+ADD_ADDRESS = 4
+ADD_ROUTE = 5
+
+class TestbedConfiguration(testbed.TestbedConfiguration):
+ pass
+
+class TestbedInstance(testbed.TestbedInstance):
+ def __init__(self, configuration):
+ self._netns = self._load_netns_module(configuration)
+ self._elements = dict()
+ self._configuration = configuration
+ self._instructions = dict({
+ CREATE: dict(),
+ SET: dict(),
+ CONNECT: dict(),
+ ADD_TRACE: dict(),
+ ADD_ADDRESS: dict(),
+ ADD_ROUTE: dict()
+ })
+ self._factories = dict({
+ "Node": list(),
+ "P2PInterface": list(),
+ "TapNodeInterface": list(),
+ "NodeInterface": list(),
+ "Switch": list(),
+ "Application": list()
+ })
+ self._connections = list()
+
+ def create(self, guid, factory_id):
+ if guid in self._instructions[CREATE]:
+ # XXX: Validation
+ raise RuntimeError("cannot add two elements with the same guid")
+ if factory_id not in self._factories:
+ # XXX: Validation
+ raise RuntimeError("%s is not an allowed factory_id" % factory_id)
+ self._instructions[CREATE][guid] = factory_id
+ self._factories[factory_id].append(guid)
+
+ def create_set(self, guid, name, value):
+ if guid not in self._instructions[SET]:
+ self._instructions[SET][guid] = dict()
+ self._instructions[SET][guid][name] = value
+
+ def connect(self, guid1, connector_type_name1, guid2,
+ connector_type_name2):
+ if not guid1 in self._instructions[CONNECT]:
+ self._instructions[CONNECT] = dict()
+ if not connector_type_name1 in self._instructions[CONNECT][guid1]:
+ self._instructions[CONNECT][guid1][connector_type_name1] = dict()
+ self._instructions[CONNECT][guid1][connector_type_name1][guid2] = \
+ connector_type_name2
+ self._connections.append((guid1, connector_type_name1, guid2,
+ connector_type_name2))
+
+ def add_trace(self, guid, trace_id):
+ if not guid in self._instructions[ADD_TRACE]:
+ self._instructions[ADD_TRACE][guid] = list()
+ self._instructions[ADD_TRACE][guid].append(trace_id)
+
+ def add_adddress(self, guid, family, address, netprefix, broadcast):
+ if not guid in self._instructions[ADD_ADDRESS]:
+ self._instructions[ADD_ADDRESS][guid] = list()
+ self._instructions[ADD_ADDRESS][guid].append((guid, family, address,
+ netprefix, broadcast))
+
+ def add_route(self, guid, family, destination, netprefix, nexthop,
+ interface):
+ if not guid in self._instructions[ADD_ROUTE]:
+ self._instructions[ADD_ROUTE][guid] = list()
+ self._instructions[ADD_ROUTE][guid].append((family, destination,
+ netprefix, nexthop, interface))
+
+ def do_create(self):
+ # nodes need to be created first
+ factories_order = ["Node", "P2PInterface", "TapNodeInterface",
+ "NodeInterface", "Switch", "Application"]
+ for guid in self._factories[factory_id] \
+ for factory_id in factories_order:
+ self._create_element(guid, factory_id)
+ # free self._factories as it is not going to be used further
+ # TODO: Check if this methods frees everithing...
+ # maybe there are still some references!
+ self._factories = None
+
+ def do_connect(self):
+ cross_connections = list()
+ for (guid1, connector_type_name1, guid2, connector_type_name2) \
+ in self._connections:
+ if guid1 not in self._elements or guid2 not in self._elements:
+ # at least one of the elements does not belong to this
+ # TestbedIntsance and so it needs to be treated as a cross
+ # testbed connection
+ cross_connections.append(guid1, connector_type_name1, guid2,
+ connector_type_name2)
+ else:
+ # TODO: do Whatever is needed to connect
+ pass
+ self._connections = cross_connections
+
+ def do_configure(self):
+ raise NotImplementedError
+ #self._object.add_route(
+ # prefix = destination,
+ # prefix_len = netprefix,
+ # nexthop = nexthop)
+
+ def do_cross_connect(self):
+ for (guid1, connector_type_name1, guid2, connector_type_name2) \
+ in self._connections:
+ # TODO: do Whatever is needed to connect
+ pass
+ # free connections list as is not going to be used further
+ self._connections = None
+
+ def set(self, time, guid, name, value):
+ raise NotImplementedError
+
+ def get(self, time, guid, name):
+ raise NotImplementedError
+
+ def start(self, time):
+ raise NotImplementedError
+
+ def action(self, time, guid, action):
+ raise NotImplementedError
+
+ def stop(self, time):
+ raise NotImplementedError
+
+ def status(self, guid):
+ raise NotImplementedError
+
+ def trace(self, guid, trace_id):
+ raise NotImplementedError
+
+ def shutdown(self):
+ raise NotImplementedError
+
+ def _netns_module(self, configuration):
+ # TODO: Do something with the configuration!!!
+ import sys
+ __import__("netns")
+ return sys.modules["netns"]
+
+ def _create_element(self, guid, factory_id):
+ paremeters = dict()
+ if guid in self._instructions[SET]:
+ parameters = self._instructions[SET][guid]
+ if guid not in self._elements.keys():
+ if factory_id == "Node":
+ self._create_node_element(guid, parameters)
+ elif factory_id == "P2PInterface":
+ self._create_p2piface_element(guid, parameters)
+ self._set_attributes(guid, parameters)
+
+ def _create_node_element(self, guid, parameters):
+ forward_X11 = False
+ if "forward_X11" in paremeters:
+ forward_X11 = parameters["forward_X11"]
+ del parameters["forward_X11"]
+ element = self._netns.Node(forward_X11 = forward_X11)
+ self._elements[guid] = element
+
+ def _create_p2piface_element(self, guid, parameters):
+ # search in the connections the node asociated with this
+ # P2PInterface and the other P2PInterface to which it is
+ # connected
+ connection =
+ node1 =
+ node2 =
+ element1, element2 = self._netns.P2PInterface.create_pair(
+ node1, node2)
+ self._elements[guid] = element1
+ self._elements[guid2] = element2
+
+ def _set_attributes(self, guid, paramenters):
+ for name, value in parameters:
+ # TODO: Validate attribute does not exist!!!
+ setattr(element, name, value)
+
+def connect_switch(switch_connector, interface_connector):
+ switch = switch_connector.container_element
+ interface = interface_connector.container_element
+ if switch.is_installed() and interface.is_installed():
+ switch._object.connect(interface._object)
+ return True
+ return False
+
+#XXX: This connection function cannot be use to transfer a file descriptor
+# to a remote tap device
+def connect_fd_local(tap_connector, fdnd_connector):
+ tap = tap_connector.container_element
+ fdnd = fdnd_connector.container_element
+ if fdnd.is_installed() and tap.is_installed():
+ socket = tap.server.modules.socket
+ passfd = tap.server.modules.passfd
+ fd = tap.file_descriptor
+ address = fdnd.socket_address
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+ sock.connect(address)
+ passfd.sendfd(sock, fd, '0')
+ # TODO: after succesful transfer, the tap device should close the fd
+ return True
+ return False
+
+connections = [
+ dict({
+ 'from' : [ "netns", "Node", "devs" ],
+ 'to' : [ "netns", "P2PInterface", "node" ],
+ 'code' : do_nothing,
+ 'can_cross' : False
+ }),
+ dict({
+ 'from' : [ "netns", "Node", "devs" ],
+ 'to' : [ "netns", "TapNodeInterface", "node" ],
+ 'code' : do_nothing,
+ 'can_cross' : False
+ }),
+ dict({
+ 'from' : [ "netns", "Node", "devs" ],
+ 'to' : [ "netns", "NodeInterface", "node" ],
+ 'code' : do_nothing,
+ 'can_cross' : False
+ }),
+ dict({
+ 'from' : [ "netns", "P2PInterface", "p2p" ],
+ 'to' : [ "netns", "P2PInterface", "p2p" ],
+ 'code' : do_nothing,
+ 'can_cross' : False
+ }),
+ dict({
+ 'from' : [ "netns", "TapNodeInterface", "fd" ],
+ 'to' : [ "ns3", "ns3::FileDescriptorNetDevice", "fd" ],
+ 'code' : connect_fd_local,
+ 'can_cross' : True
+ }),
+ dict({
+ 'from' : [ "netns", "Switch", "devs" ],
+ 'to' : [ "netns", "NodeInterface", "switch" ],
+ 'code' : connect_switch,
+ 'can_cross' : False
+ }),
+ dict({
+ 'from' : [ "netns", "Node", "apps" ],
+ 'to' : [ "netns", "Application", "node" ],
+ 'code' : do_nothing,
+ 'can_cross' : False
+ })
+]
+
+class TapNodeInterface(object):
+ def __init__(self):
+ # GET THE NODE!
+ self._object = node._object.add_tap()
+
+class NodeInterface(object):
+ def __init__(self):
+ # GET NODE
+ self._object = n.add_if()
+
+class Switch(Topo_ChannelMixin, NetnsElement):
+ def __init__(self, factory, server, container = None):
+ self._object = self.server.modules.netns.Switch()
+
+class NetnsApplication(NetnsElement):
+ def __init__(self, factory, server, container = None):
+ super(NetnsApplication, self).__init__(factory, server, container)
+ # attributes
+ self.add_string_attribute(name = "command",
+ help = "Command name")
+ self.add_string_attribute(name = "user",
+ help = "system user")
+ self.add_string_attribute(name = "stdin",
+ help = "Standard input")
+ #traces
+ stdout = StdTrace(
+ name='StdoutTrace',
+ help='Application standard output',
+ filename='stdout.txt',
+ element=self)
+ stderr = StdTrace(
+ name='StderrTrace',
+ help='Application standard error',
+ filename='stderr.txt',
+ element=self)
+ self._add_trace(stdout)
+ self._add_trace(stderr)
+
+ def start(self):
+ user = self.get_attribute("user").value
+
+ stdin = stdout = stderr = None
+ if self.get_attribute('stdin').value:
+ filename = self.get_attribute('stdin')
+ stdin = self.server.modules.__builtin__.open(filename, 'rb')
+
+ trace = self.get_trace("StdoutTrace")
+ if trace.is_enabled:
+ filename = trace.real_filepath
+ stdout = self.server.modules.__builtin__.open(filename, 'wb')
+
+ trace = self.get_trace("StderrTrace")
+ if trace.is_enabled:
+ filename = trace.real_filepath
+ stderr = self.server.modules.__builtin__.open(filename, 'wb')
+
+ cnctr = self.connector("node")
+ node = iter(cnctr.connections).next().get_other(cnctr)\
+ .container_element
+ force_install(node)
+ n = node._object
+ command = self.get_attribute('command').value
+ targets = re.findall(r"%target:(.*?)%", command)
+ for target in targets:
+ try:
+ (family, address, port) = resolve_netref(target, AF_INET,
+ self.server.experiment )
+ command = command.replace("%%target:%s%%" % target, address.address)
+ except:
+ continue
+
+ self._object = n.Popen(command, shell = True, stdout = stdout, stdin = stdin,
+ stderr = stderr, user = user)
+
+ def is_completed(self):
+ if self._object is not None:
+ returncode = self._object.poll()
+ if returncode is not None:
+ return True
+ return False
+
+class StdTrace(Trace):
+ def install(self):
+ pass
+
+ @property
+ def real_filepath(self):
+ filename = self.get_attribute("Filename").value
+ return self.element.server.get_trace_filepath(filename)
+
+ def read_trace(self):
+ filename = self.get_attribute("Filename").value
+ return self.element.server.read_trace(filename)
+
+def force_install(object):
+ if not object.is_installed():
+ object.install()
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim:ts=4:sw=4:et:ai:sts=4
+
+class GraphicalInfo(object):
+ """ This class allows to describe the position and dimensions of a
+ 2D object in a GUI canvas"""
+ def __init__(self, label):
+ self.x = 0.0
+ self.y = 0.0
+ self.width = 0.0
+ self.height = 0.0
+ self.label = label
+
self.box_data_to_xml(doc, elements_tags, guid, data)
doc.appendChild(exp_tag)
xml = doc.toprettyxml(indent=" ", encoding="UTF-8")
+ print xml
return xml
def testbed_data_to_xml(self, doc, parent_tag, guid, data):
def factory_attributes_data_to_xml(self, doc, parent_tag, guid, data):
factory_attributes_tag = doc.createElement("factory_attributes")
- parent_tag.appendChild(factory_attributes_tag)
for (name, value) in data.get_factory_attribute_data(guid):
factory_attribute_tag = doc.createElement("factory_attribute")
factory_attributes_tag.appendChild(factory_attribute_tag)
factory_attribute_tag.setAttribute("name", name)
factory_attribute_tag.setAttribute("value", str(value))
factory_attribute_tag.setAttribute("type", self.type_to_standard(value))
+ if factory_attributes_tag.hasChildNodes():
+ parent_tag.appendChild(factory_attributes_tag)
def attributes_data_to_xml(self, doc, parent_tag, guid, data):
attributes_tag = doc.createElement("attributes")
- parent_tag.appendChild(attributes_tag)
for name, value in data.get_attribute_data(guid):
attribute_tag = doc.createElement("attribute")
attributes_tag.appendChild(attribute_tag)
attribute_tag.setAttribute("name", name)
attribute_tag.setAttribute("value", str(value))
attribute_tag.setAttribute("type", self.type_to_standard(value))
+ if attributes_tag.hasChildNodes():
+ parent_tag.appendChild(attributes_tag)
def traces_data_to_xml(self, doc, parent_tag, guid, data):
traces_tag = doc.createElement("traces")
- parent_tag.appendChild(traces_tag)
for name in data.get_trace_data(guid):
trace_tag = doc.createElement("trace")
traces_tag.appendChild(trace_tag)
trace_tag.setAttribute("name", name)
+ if traces_tag.hasChildNodes():
+ parent_tag.appendChild(traces_tag)
def addresses_data_to_xml(self, doc, parent_tag, guid, data):
addresses_tag = doc.createElement("addresses")
- parent_tag.appendChild(addresses_tag)
for (autoconfigure, address, family, netprefix, broadcast) \
in data.get_address_data(guid):
address_tag = doc.createElement("address")
address_tag.setAttribute("NetPrefix", str(netprefix))
if broadcast:
address_tag.setAttribute("Broadcast", str(broadcast))
+ if addresses_tag.hasChildNodes():
+ parent_tag.appendChild(addresses_tag)
def routes_data_to_xml(self, doc, parent_tag, guid, data):
routes_tag = doc.createElement("routes")
- parent_tag.appendChild(routes_tag)
for (family, destination, netprefix, nexthop, interface) \
in data.get_route_data(guid):
route_tag = doc.createElement("route")
route_tag.setAttribute("NetPrefix", str(netprefix))
route_tag.setAttribute("NextHop", str(nexthop))
route_tag.setAttribute("Interface", str(interface))
+ if routes_tag.hasChildNodes():
+ parent_tag.appendChild(routes_tag)
def connections_data_to_xml(self, doc, parent_tag, guid, data):
connections_tag = doc.createElement("connections")
- parent_tag.appendChild(connections_tag)
for (connector_type_name, other_guid, other_connector_type_name) \
in data.get_connection_data(guid):
connection_tag = doc.createElement("connection")
connection_tag.setAttribute("other_guid", str(other_guid))
connection_tag.setAttribute("other_connector",
other_connector_type_name)
+ if connections_tag.hasChildNodes():
+ parent_tag.appendChild(connections_tag)
def from_xml(self, experiment_description, xml):
data = ExperimentData()
for testbed_tag in testbed_tag_list:
if testbed_tag.nodeType == doc.ELEMENT_NODE:
testbed_guid = int(testbed_tag.getAttribute("guid"))
- self.testbed_data_from_xml(testbed_tag, data)
elements_tag = testbed_tag.getElementsByTagName("elements")[0]
+ elements_tag = testbed_tag.removeChild(elements_tag)
+ self.testbed_data_from_xml(testbed_tag, data)
element_tag_list = elements_tag.getElementsByTagName("element")
for element_tag in element_tag_list:
if element_tag.nodeType == doc.ELEMENT_NODE: