diff --git a/framework/python/src/net_orc/network_orchestrator.py b/framework/python/src/net_orc/network_orchestrator.py index 8126d0738..b83feffe4 100644 --- a/framework/python/src/net_orc/network_orchestrator.py +++ b/framework/python/src/net_orc/network_orchestrator.py @@ -193,6 +193,7 @@ def _device_discovered(self, mac_addr): LOGGER.info( f'Device with mac addr {device.mac_addr} has obtained IP address ' f'{device.ip_addr}') + # self._ovs.add_arp_inspection_filter(ip_address=device.ip_addr,mac_address=device.mac_addr) self._start_device_monitor(device) @@ -661,6 +662,10 @@ def _attach_service_to_network(self, net_module): ' to internet bridge ' + DEVICE_BRIDGE + '. Exiting.') sys.exit(1) + def remove_arp_filters(self): + LOGGER.info('Removing ARP inspection filters') + self._ovs.delete_arp_inspection_filter() + def restore_net(self): LOGGER.info('Clearing baseline network') diff --git a/framework/python/src/net_orc/ovs_control.py b/framework/python/src/net_orc/ovs_control.py index 80f76e85f..015d6b7a2 100644 --- a/framework/python/src/net_orc/ovs_control.py +++ b/framework/python/src/net_orc/ovs_control.py @@ -18,7 +18,9 @@ DEVICE_BRIDGE = 'tr-d' INTERNET_BRIDGE = 'tr-c' LOGGER = logger.get_logger('ovs_ctrl') - +DEVICER_ARP_COOKIE = '1000' +UNKNOWN_ARP_COOKIE = '1183' +CONTAINER_MAC_PREFIX = '9a:02:57:1e:8f' class OVSControl: """OVS Control""" @@ -51,6 +53,12 @@ def add_port(self, port, bridge_name): add-port {bridge_name} {port}""") return success + def delete_flow(self, bridge_name, flow): + # Delete a flow from the bridge using ovs-ofctl commands + LOGGER.debug(f'Deleting flow {flow} from bridge: {bridge_name}') + success = util.run_command(f'ovs-ofctl del-flows {bridge_name} \'{flow}\'') + return success + def get_bridge_ports(self, bridge_name): # Get a list of all the ports on a bridge response = util.run_command(f'ovs-vsctl list-ports {bridge_name}', @@ -125,6 +133,13 @@ def create_baseline_net(self, verify=True): self.add_flow(bridge_name=DEVICE_BRIDGE, flow='table=0, dl_dst=01:80:c2:00:00:03, actions=flood') + # Add a DHCP snooping equivalent to the device bridge + # ToDo Define these IP's dynamically + dhcp_server_primary_ip = '10.10.10.2' + dhcp_server_secondary_ip = '10.10.10.3' + self.add_dhcp_filters(dhcp_server_primary_ip=dhcp_server_primary_ip, + dhcp_server_secondary_ip=dhcp_server_secondary_ip) + # Set ports up self.set_bridge_up(DEVICE_BRIDGE) self.set_bridge_up(INTERNET_BRIDGE) @@ -136,6 +151,49 @@ def create_baseline_net(self, verify=True): else: return None + def add_dhcp_filters(self,dhcp_server_primary_ip,dhcp_server_secondary_ip): + + # Allow DHCP traffic from primary server + allow_primary_dhcp_server = ( + f'table=0, dl_type=0x800, priority=65535, tp_src=67, tp_dst=68, nw_src={dhcp_server_primary_ip}, actions=normal') + self.add_flow(bridge_name=DEVICE_BRIDGE,flow=allow_primary_dhcp_server) + + # Allow DHCP traffic from secondary server + allow_secondary_dhcp_server = ( + f'table=0, dl_type=0x800, priority=65535, tp_src=67, tp_dst=68, nw_src={dhcp_server_secondary_ip}, actions=normal') + self.add_flow(bridge_name=DEVICE_BRIDGE,flow=allow_secondary_dhcp_server) + + # Drop DHCP packets not associated with known servers + drop_dhcp_flow = 'table=0, dl_type=0x800, priority=0, tp_src=67, tp_dst=68, actions=drop' + self.add_flow(bridge_name=DEVICE_BRIDGE,flow=drop_dhcp_flow) + + def add_arp_inspection_filter(self,ip_address,mac_address): + # Allow ARP packets with known MAC-to-IP mappings + allow_known_arps= f'table=0, cookie={DEVICER_ARP_COOKIE}, priority=65535, arp, arp_tpa={ip_address}, arp_tha={mac_address}, action=normal' + self.add_flow(bridge_name=DEVICE_BRIDGE,flow=allow_known_arps) + + DHCP1_MAC = f'{CONTAINER_MAC_PREFIX}:02' + DHCP2_MAC = f'{CONTAINER_MAC_PREFIX}:03' + DHCP1_IP = '10.10.10.2' + DHCP2_IP = '10.10.10.3' + + dhcp_1_arps= f'table=0, priority=65535, arp, arp_tpa={DHCP1_IP}, arp_tha={DHCP1_MAC}, action=normal' + dhcp_2_arps= f'table=0, priority=65535, arp, arp_tpa={DHCP2_IP}, arp_tha={DHCP2_MAC}, action=normal' + self.add_flow(bridge_name=DEVICE_BRIDGE,flow=dhcp_1_arps) + self.add_flow(bridge_name=DEVICE_BRIDGE,flow=dhcp_2_arps) + + # Drop ARP packets with unknown MAC-to-IP mappings + drop_unknown_arps = ( + f'table=0, cookie={UNKNOWN_ARP_COOKIE} priority=100, arp, ' + f'action=drop' + ) + self.add_flow(bridge_name=DEVICE_BRIDGE,flow=drop_unknown_arps) + + def delete_arp_inspection_filter(self): + self.delete_flow(bridge_name=DEVICE_BRIDGE,flow=f'cookie={DEVICER_ARP_COOKIE}/-1') + self.delete_flow(bridge_name=DEVICE_BRIDGE,flow=f'cookie={UNKNOWN_ARP_COOKIE}/-1') + + def delete_bridge(self, bridge_name): LOGGER.debug('Deleting OVS Bridge: ' + bridge_name) # Delete the bridge using ovs-vsctl commands diff --git a/framework/python/src/test_orc/test_orchestrator.py b/framework/python/src/test_orc/test_orchestrator.py index a81fca4fd..143243d56 100644 --- a/framework/python/src/test_orc/test_orchestrator.py +++ b/framework/python/src/test_orc/test_orchestrator.py @@ -326,6 +326,9 @@ def _run_test_module(self, module): client = docker.from_env() + # if module.name == 'connection': + # self._net_orc.remove_arp_filters() + module.container = client.containers.run( module.image_name, auto_remove=True,