def create_flows_from_rule_and_port(rule, port): ethertype = rule['ethertype'] direction = rule['direction'] dst_ip_prefix = rule.get('dest_ip_prefix') src_ip_prefix = rule.get('source_ip_prefix') flow_template = { 'priority': 70, 'dl_type': ovsfw_consts.ethertype_to_dl_type_map[ethertype], 'reg_port': port.ofport, } if is_valid_prefix(dst_ip_prefix): flow_template[FLOW_FIELD_FOR_IPVER_AND_DIRECTION[( utils.get_ip_version(dst_ip_prefix), firewall.EGRESS_DIRECTION)] ] = dst_ip_prefix if is_valid_prefix(src_ip_prefix): flow_template[FLOW_FIELD_FOR_IPVER_AND_DIRECTION[( utils.get_ip_version(src_ip_prefix), firewall.INGRESS_DIRECTION)] ] = src_ip_prefix flows = create_protocol_flows(direction, flow_template, port, rule) return flows
def create_flows_from_rule_and_port(rule, port, conjunction=False): """Create flows from given args. For description of the optional conjunction arg, see flow_priority_offset. """ ethertype = rule['ethertype'] direction = rule['direction'] dst_ip_prefix = rule.get('dest_ip_prefix') src_ip_prefix = rule.get('source_ip_prefix') flow_template = { 'priority': 70 + flow_priority_offset(rule, conjunction), 'dl_type': ovsfw_consts.ethertype_to_dl_type_map[ethertype], 'reg_port': port.ofport, } if is_valid_prefix(dst_ip_prefix): flow_template[FLOW_FIELD_FOR_IPVER_AND_DIRECTION[( utils.get_ip_version(dst_ip_prefix), n_consts.EGRESS_DIRECTION)] ] = dst_ip_prefix if is_valid_prefix(src_ip_prefix): flow_template[FLOW_FIELD_FOR_IPVER_AND_DIRECTION[( utils.get_ip_version(src_ip_prefix), n_consts.INGRESS_DIRECTION)] ] = src_ip_prefix flows = create_protocol_flows(direction, flow_template, port, rule) return flows
def fdb_ip_entry_exists(self, mac, ip, interface): ip_version = utils.get_ip_version(ip) entry = ip_lib.dump_neigh_entries(ip_version, interface, dst=ip, lladdr=mac) return entry != []
def test_add_rule_priority(self): priority = 12345 ip_addresses = ['192.168.200.252', '2001::252'] for ip_address in ip_addresses: ip_version = common_utils.get_ip_version(ip_address) ip_lenght = common_utils.get_network_length(ip_version) ip_family = common_utils.get_socket_address_family(ip_version) priv_ip_lib.add_ip_rule(self.namespace, priority=priority, src=ip_address, src_len=ip_lenght, family=ip_family) rules = ip_lib.list_ip_rules(self.namespace, ip_version) self._check_rules( rules, ['priority', 'from'], [str(priority), ip_address], 'priority %s and "from" IP address %s' % (priority, ip_address)) priv_ip_lib.delete_ip_rule(self.namespace, priority=priority, src=ip_address, src_len=ip_lenght, family=ip_family) rules = ip_lib.list_ip_rules(self.namespace, ip_version) self.assertFalse( self._check_rules(rules, ['priority', 'from'], [str(priority), ip_address], raise_exception=False))
def _check_routes(self, cidrs, table=None, gateway=None, metric=None, scope=None): table = table or iproute_linux.DEFAULT_TABLE if not scope: scope = 'universe' if gateway else 'link' scope = priv_ip_lib._get_scope_name(scope) for cidr in cidrs: ip_version = common_utils.get_ip_version(cidr) if ip_version == n_cons.IP_VERSION_6 and not metric: metric = ipdb_routes.IP6_RT_PRIO_USER if ip_version == n_cons.IP_VERSION_6: scope = 0 routes = priv_ip_lib.list_ip_routes(self.namespace, ip_version) for route in routes: ip = ip_lib.get_attr(route, 'RTA_DST') mask = route['dst_len'] if not (ip == str(netaddr.IPNetwork(cidr).ip) and mask == netaddr.IPNetwork(cidr).cidr.prefixlen): continue self.assertEqual(table, route['table']) self.assertEqual( priv_ip_lib._IP_VERSION_FAMILY_MAP[ip_version], route['family']) self.assertEqual(gateway, ip_lib.get_attr(route, 'RTA_GATEWAY')) self.assertEqual(metric, ip_lib.get_attr(route, 'RTA_PRIORITY')) self.assertEqual(scope, route['scope']) break else: self.fail('CIDR %s not found in the list of routes' % cidr)
def test_add_rule_table(self): table = 212 ip_addresses = ['192.168.200.251', '2001::251'] for ip_address in ip_addresses: ip_version = common_utils.get_ip_version(ip_address) ip_lenght = common_utils.get_network_length(ip_version) ip_family = common_utils.get_socket_address_family(ip_version) priv_ip_lib.add_ip_rule(self.namespace, table=table, src=ip_address, src_len=ip_lenght, family=ip_family) rules = ip_lib.list_ip_rules(self.namespace, ip_version) self._check_rules( rules, ['table', 'from'], [str(table), ip_address], 'table %s and "from" IP address %s' % (table, ip_address)) priv_ip_lib.delete_ip_rule(self.namespace, table=table, src=ip_address, src_len=ip_lenght, family=ip_family) rules = ip_lib.list_ip_rules(self.namespace, ip_version) self.assertFalse( self._check_rules(rules, ['table', 'from'], [str(table), ip_address], raise_exception=False))
def delete_gateway(self, gateway, table=None): ip_version = common_utils.get_ip_version(gateway) args = ['del', 'default', 'via', gateway] args += self._dev_args() args += self._table_args(table) self._run_as_root_detect_device_not_found([ip_version], tuple(args))
def test_add_route_metric(self): metrics = (None, 1, 10, 255) for cidr in self.cidrs: for metric in metrics: self.device.route.add_route(cidr, metric=metric) ip_version = utils.get_ip_version(cidr) self._assert_route(ip_version, cidr=cidr, metric=metric)
def test_add_route_table(self): tables = (None, 1, 253, 254, 255) for cidr in self.cidrs: for table in tables: self.device.route.add_route(cidr, table=table) ip_version = utils.get_ip_version(cidr) self._assert_route(ip_version, cidr=cidr, table=table)
def create_flows_for_ip_address(ip_address, direction, ethertype, vlan_tag, conj_ids): """Create flows from a rule and an ip_address derived from remote_group_id """ ip_prefix = str(netaddr.IPNetwork(ip_address).cidr) flow_template = { 'priority': 70, 'dl_type': ovsfw_consts.ethertype_to_dl_type_map[ethertype], 'reg_net': vlan_tag, # needed for project separation } ip_ver = utils.get_ip_version(ip_prefix) if direction == firewall.EGRESS_DIRECTION: flow_template['table'] = ovs_consts.RULES_EGRESS_TABLE elif direction == firewall.INGRESS_DIRECTION: flow_template['table'] = ovs_consts.RULES_INGRESS_TABLE flow_template[FLOW_FIELD_FOR_IPVER_AND_DIRECTION[( ip_ver, direction)]] = ip_prefix return substitute_conjunction_actions([flow_template], 1, conj_ids)
def _update_interface_ip_details(self, destination, source, ips, gateway): dst_device = self.ip.device(destination) src_device = self.ip.device(source) # Append IP's to bridge if necessary if ips: for ip in ips: # If bridge ip address already exists, then don't add # otherwise will report error to = utils.cidr_to_ip(ip['cidr']) if not dst_device.addr.list(to=to): dst_device.addr.add(cidr=ip['cidr']) if gateway: # Ensure that the gateway can be updated by changing the metric metric = 100 ip_version = utils.get_ip_version(gateway['cidr']) if gateway['metric'] != ip_lib.IP_ROUTE_METRIC_DEFAULT[ip_version]: metric = gateway['metric'] - 1 dst_device.route.add_gateway(gateway=gateway['via'], metric=metric) src_device.route.delete_gateway(gateway=gateway['via']) # Remove IP's from interface if ips: for ip in ips: src_device.addr.delete(cidr=ip['cidr'])
def delete_gateway(self, gateway, table=None): ip_version = common_utils.get_ip_version(gateway) args = ['del', 'default', 'via', gateway] args += self._dev_args() args += self._table_args(table) self._run_as_root_detect_device_not_found([ip_version], args)
def create_flows_for_ip_address(ip_address, direction, ethertype, vlan_tag, conj_ids): """Create flows from a rule and an ip_address derived from remote_group_id """ ip_prefix = str(netaddr.IPNetwork(ip_address).cidr) flow_template = { 'priority': 70, 'dl_type': ovsfw_consts.ethertype_to_dl_type_map[ethertype], 'reg_net': vlan_tag, # needed for project separation } ip_ver = utils.get_ip_version(ip_prefix) if direction == firewall.EGRESS_DIRECTION: flow_template['table'] = ovs_consts.RULES_EGRESS_TABLE elif direction == firewall.INGRESS_DIRECTION: flow_template['table'] = ovs_consts.RULES_INGRESS_TABLE flow_template[FLOW_FIELD_FOR_IPVER_AND_DIRECTION[(ip_ver, direction)]] = ip_prefix return substitute_conjunction_actions([flow_template], 1, conj_ids)
def test_get_and_delete_gateway(self): gateways = (str(netaddr.IPNetwork(self.device_cidr_ipv4).ip), str(netaddr.IPNetwork(self.device_cidr_ipv6).ip + 1)) scopes = ('global', 'site', 'link') metrics = (None, 1, 255) tables = (None, 1, 254, 255) for gateway, scope, metric, table in itertools.product( gateways, scopes, metrics, tables): ip_version = utils.get_ip_version(gateway) self.device.route.add_gateway(gateway, scope=scope, metric=metric, table=table) self._assert_route(ip_version, cidr=None, via=gateway, scope=scope, metric=metric, table=table) self.assertEqual( gateway, self.device.route.get_gateway(ip_version=ip_version, table=table)['via']) self.device.route.delete_gateway(gateway, table=table, scope=scope) self.assertIsNone( self.device.route.get_gateway(ip_version=ip_version, table=table))
def add_gateway(self, gateway, metric=None, table=None): ip_version = common_utils.get_ip_version(gateway) args = ['replace', 'default', 'via', gateway] if metric: args += ['metric', metric] args += self._dev_args() args += self._table_args(table) self._as_root([ip_version], tuple(args))
def has_expected_arp_entry(device_name, namespace, ip, mac): ip_version = utils.get_ip_version(ip) entry = ip_lib.dump_neigh_entries(ip_version, device_name, namespace, dst=ip, lladdr=mac) return entry != []
def test_add_route_gateway(self): gateways = (str(netaddr.IPNetwork(self.device_cidr_ipv4).ip), str(netaddr.IPNetwork(self.device_cidr_ipv6).ip + 1)) for gateway in gateways: ip_version = utils.get_ip_version(gateway) self.device.route.add_gateway(gateway) self._assert_route(ip_version, cidr=None, via=gateway, scope='global')
def _assert_route(self, ip_version, table=None, source_prefix=None, cidr=None, scope=None, via=None, metric=None, not_in=False): if not_in: fn = lambda: cmp not in self.device.route.list_routes(ip_version, table=table) msg = 'Route found: %s' else: fn = lambda: cmp in self.device.route.list_routes(ip_version, table=table) msg = 'Route not found: %s' if cidr: ip_version = utils.get_ip_version(cidr) else: ip_version = utils.get_ip_version(via) cidr = constants.IP_ANY[ip_version] if constants.IP_VERSION_6 == ip_version: scope = ip_lib.IP_ADDRESS_SCOPE[0] elif not scope: scope = 'global' if via else 'link' if not metric: metric = ip_lib.IP_ROUTE_METRIC_DEFAULT[ip_version] table = table or iproute_linux.DEFAULT_TABLE table = ip_lib.IP_RULE_TABLES_NAMES.get(table, table) cmp = { 'table': table, 'cidr': cidr, 'source_prefix': source_prefix, 'scope': scope, 'device': 'test_device', 'via': via, 'metric': metric, 'proto': 'static' } try: utils.wait_until_true(fn, timeout=5) except utils.WaitTimeout: raise self.fail(msg % cmp)
def start(self): if self.proc and self.proc.is_running: raise RuntimeError("This pinger has already a running process") ip_version = common_utils.get_ip_version(self.address) ping_exec = 'ping' if ip_version == 4 else 'ping6' cmd = [ping_exec, self.address, '-W', str(self.timeout)] if self.count: cmd.extend(['-c', str(self.count)]) self.proc = RootHelperProcess(cmd, namespace=self.namespace)
def test_add_route_via(self): gateway_ipv4 = str(netaddr.IPNetwork(self.device_cidr_ipv4).ip) gateway_ipv6 = str(netaddr.IPNetwork(self.device_cidr_ipv6).ip + 1) for cidr in self.cidrs: ip_version = utils.get_ip_version(cidr) gateway = (gateway_ipv4 if ip_version == constants.IP_VERSION_4 else gateway_ipv6) self.device.route.add_route(cidr, via=gateway) self._assert_route(ip_version, cidr=cidr, via=gateway)
def get_gateway_ips(gateway_port): gw_ips = {} if gateway_port: for subnet in gateway_port.get('subnets', []): gateway_ip = subnet.get('gateway_ip', None) if gateway_ip: ip_version = common_utils.get_ip_version(gateway_ip) gw_ips[ip_version] = gateway_ip return gw_ips
def _add_default_gateway_for_fip(self, gw_ip, ip_device, tbl_index): """Adds default gateway for fip based on the tbl_index passed.""" if tbl_index is None: ip_version = common_utils.get_ip_version(gw_ip) tbl_index_list = self.get_fip_table_indexes(ip_version) for tbl_index in tbl_index_list: ip_device.route.add_gateway(gw_ip, table=tbl_index) else: ip_device.route.add_gateway(gw_ip, table=tbl_index)
def delete(self, ip, **kwargs): ip_version = common_utils.get_ip_version(ip) # TODO(Carl) ip ignored in delete, okay in general? canonical_kwargs = self._make_canonical(ip_version, kwargs) args_tuple = self._make__flat_args_tuple('del', **canonical_kwargs) self._as_root([ip_version], args_tuple)
def _wait_for_metadata_provisioned_if_needed(self, port_id): """Wait for metadata service to be provisioned. Wait until metadata service has been setup for this port in the chassis it resides. If metadata is disabled or DHCP is not enabled for its subnets, this function will return right away. """ if config.is_ovn_metadata_enabled() and self._sb_ovn: # Wait until metadata service has been setup for this port in the # chassis it resides. result = ( self._sb_ovn.get_logical_port_chassis_and_datapath(port_id)) if not result: LOG.warning("Logical port %s doesn't exist in OVN", port_id) return chassis, datapath = result if not chassis: LOG.warning("Logical port %s is not bound to a " "chassis", port_id) return # Check if the port belongs to some IPv4 subnet with DHCP enabled. context = n_context.get_admin_context() port = self._plugin.get_port(context, port_id) port_subnet_ids = set(ip['subnet_id'] for ip in port['fixed_ips'] if n_utils.get_ip_version(ip['ip_address']) == const.IP_VERSION_4) if not port_subnet_ids: # The port doesn't belong to any IPv4 subnet return subnets = self._plugin.get_subnets( context, filters=dict(network_id=[port['network_id']], ip_version=[4], enable_dhcp=True)) subnet_ids = set(s['id'] for s in subnets if s['id'] in port_subnet_ids) if not subnet_ids: return try: n_utils.wait_until_true( lambda: datapath in self._sb_ovn. get_chassis_metadata_networks(chassis), timeout=METADATA_READY_WAIT_TIMEOUT, exception=MetadataServiceReadyWaitTimeoutException) except MetadataServiceReadyWaitTimeoutException: # If we reach this point it means that metadata agent didn't # provision the datapath for this port on its chassis. Either # the agent is not running or it crashed. We'll complete the # provisioning block though. LOG.warning( "Metadata service is not ready for port %s, check" " networking-ovn-metadata-agent status/logs.", port_id)
def test_add_route_via_ipv4(self): cidrs = ['192.168.0.0/24', '172.90.0.0/16', '10.0.0.0/8'] int_cidr = '192.168.20.1/24' int_ip_address = str(netaddr.IPNetwork(int_cidr).ip) self.device.addr.add(int_cidr) for cidr in cidrs: ip_version = common_utils.get_ip_version(cidr) priv_ip_lib.add_ip_route(self.namespace, cidr, ip_version, via=int_ip_address) self._check_routes(cidrs, gateway=int_ip_address)
def test_add_route_via_ipv6(self): cidrs = ['2001:db8::/64', 'faaa::/96'] int_cidr = 'fd00::1/64' via_ip = 'fd00::2' self.device.addr.add(int_cidr) for cidr in cidrs: ip_version = common_utils.get_ip_version(cidr) priv_ip_lib.add_ip_route(self.namespace, cidr, ip_version, via=via_ip) self._check_routes(cidrs, gateway=via_ip)
def delete_route(self, cidr, via=None, table=None, **kwargs): ip_version = common_utils.get_ip_version(cidr) args = ['del', cidr] if via: args += ['via', via] args += self._dev_args() args += self._table_args(table) for k, v in kwargs.items(): args += [k, v] self._run_as_root_detect_device_not_found([ip_version], args)
def delete_route(self, cidr, via=None, table=None, **kwargs): ip_version = common_utils.get_ip_version(cidr) args = ['del', cidr] if via: args += ['via', via] args += self._dev_args() args += self._table_args(table) for k, v in kwargs.items(): args += [k, v] self._run_as_root_detect_device_not_found([ip_version], tuple(args))
def _test_icmp_connectivity(self, direction, protocol, src_port, dst_port): src_namespace, ip_address = self._get_namespace_and_address(direction) ip_version = common_utils.get_ip_version(ip_address) icmp_timeout = ICMP_VERSION_TIMEOUTS[ip_version] try: net_helpers.assert_ping(src_namespace, ip_address, timeout=icmp_timeout) except RuntimeError: raise ConnectionTesterException( "ICMP packets can't get from %s namespace to %s address" % ( src_namespace, ip_address))
def start(self): if self.proc and self.proc.is_running: raise RuntimeError("This pinger has already a running process") ip_version = common_utils.get_ip_version(self.address) ping_exec = 'ping' if ip_version == n_const.IP_VERSION_4 else 'ping6' cmd = [ping_exec, self.address, '-W', str(self.timeout)] if self.count: cmd.extend(['-c', str(self.count)]) if self.interval: cmd.extend(['-i', str(self.interval)]) self.proc = RootHelperProcess(cmd, namespace=self.namespace)
def _add_route_device_and_check(self, table=None, metric=None, scope='link'): cidrs = ['192.168.0.0/24', '172.90.0.0/16', '10.0.0.0/8', '2001:db8::/64'] for cidr in cidrs: ip_version = common_utils.get_ip_version(cidr) priv_ip_lib.add_ip_route(self.namespace, cidr, ip_version, device=self.device_name, table=table, metric=metric, scope=scope) self._check_routes(cidrs, table=table, metric=metric, scope=scope)
def add_neigh_entry(ip_address, mac_address, device, namespace=None, **kwargs): """Add a neighbour entry. :param ip_address: IP address of entry to add :param mac_address: MAC address of entry to add :param device: Device name to use in adding entry :param namespace: The name of the namespace in which to add the entry """ ip_version = common_utils.get_ip_version(ip_address) privileged.add_neigh_entry(ip_version, ip_address, mac_address, device, namespace, **kwargs)
def test_list_onlink_routes_ipv4(self): cidr_ipv4 = [] for cidr in self.cidrs: if utils.get_ip_version(cidr) == constants.IP_VERSION_4: cidr_ipv4.append(cidr) self.device.route.add_onlink_route(cidr) for cidr in cidr_ipv4: self._assert_route(constants.IP_VERSION_4, cidr=cidr) routes = self.device.route.list_onlink_routes(constants.IP_VERSION_4) self.assertEqual(len(cidr_ipv4), len(routes))
def add(self, ip, **kwargs): ip_version = common_utils.get_ip_version(ip) # In case if we need to add in a rule based on incoming # interface we don't need to pass in the ip. if not kwargs.get('iif'): kwargs.update({'from': ip}) canonical_kwargs = self._make_canonical(ip_version, kwargs) if not self._exists(ip_version, **canonical_kwargs): args_tuple = self._make__flat_args_tuple('add', **canonical_kwargs) self._as_root([ip_version], args_tuple)
def test_delete_route(self): scopes = ('global', 'site', 'link') tables = (None, 1, 254, 255) for cidr, scope, table in itertools.product( self.cidrs, scopes, tables): ip_version = utils.get_ip_version(cidr) self.device.route.add_route(cidr, table=table, scope=scope) self._assert_route(ip_version, cidr=cidr, scope=scope, table=table) self.device.route.delete_route(cidr, table=table, scope=scope) self._assert_route(ip_version, cidr=cidr, scope=scope, table=table, not_in=True)
def _get_port_devicename_scopemark(self, ports, name_generator): devicename_scopemark = {lib_constants.IP_VERSION_4: dict(), lib_constants.IP_VERSION_6: dict()} for p in ports: device_name = name_generator(p['id']) ip_cidrs = common_utils.fixed_ip_cidrs(p['fixed_ips']) port_as_marks = self.get_port_address_scope_mark(p) for ip_version in {common_utils.get_ip_version(cidr) for cidr in ip_cidrs}: devicename_scopemark[ip_version][device_name] = ( port_as_marks[ip_version]) return devicename_scopemark
def delete(self, ip, **kwargs): ip_version = common_utils.get_ip_version(ip) # In case we need to delete a rule based on an incoming # interface, pass the "any" IP address, for example, 0.0.0.0/0, # else pass the given IP. if kwargs.get('iif'): kwargs.update({'from': constants.IP_ANY[ip_version]}) else: kwargs.update({'from': ip}) canonical_kwargs = self._make_canonical(ip_version, kwargs) args_tuple = self._make__flat_args_tuple('del', **canonical_kwargs) self._as_root([ip_version], args_tuple)
def test_add_rule_ip(self): ip_addresses = ['192.168.200.250', '2001::250'] for ip_address in ip_addresses: ip_version = common_utils.get_ip_version(ip_address) ip_lenght = common_utils.get_network_length(ip_version) ip_family = common_utils.get_socket_address_family(ip_version) priv_ip_lib.add_ip_rule(self.namespace, src=ip_address, src_len=ip_lenght, family=ip_family) rules = ip_lib.list_ip_rules(self.namespace, ip_version) self._check_rules(rules, ['from'], [ip_address], '"from" IP address %s' % ip_address) priv_ip_lib.delete_ip_rule(self.namespace, family=ip_family, src=ip_address, src_len=ip_lenght) rules = ip_lib.list_ip_rules(self.namespace, ip_version) self.assertFalse( self._check_rules(rules, ['from'], [ip_address], raise_exception=False))
def create_flows_for_ip_address(ip_address, direction, ethertype, vlan_tag, conj_ids): """Create flows from a rule and an ip_address derived from remote_group_id """ # Group conj_ids per priority. conj_id_lists = [[] for i in range(4)] for conj_id in conj_ids: conj_id_lists[ _flow_priority_offset_from_conj_id(conj_id)].append(conj_id) ip_prefix = str(netaddr.IPNetwork(ip_address).cidr) flow_template = { 'dl_type': ovsfw_consts.ethertype_to_dl_type_map[ethertype], 'reg_net': vlan_tag, # needed for project separation } ip_ver = utils.get_ip_version(ip_prefix) if direction == n_consts.EGRESS_DIRECTION: flow_template['table'] = ovs_consts.RULES_EGRESS_TABLE elif direction == n_consts.INGRESS_DIRECTION: flow_template['table'] = ovs_consts.RULES_INGRESS_TABLE flow_template[FLOW_FIELD_FOR_IPVER_AND_DIRECTION[( ip_ver, direction)]] = ip_prefix result = [] for offset, conj_id_list in enumerate(conj_id_lists): if not conj_id_list: continue flow_template['priority'] = 70 + offset result.extend( substitute_conjunction_actions([flow_template], 1, conj_id_list)) return result
def get_ip_version(ip_or_cidr): return common_utils.get_ip_version(ip_or_cidr)
def delete(self, cidr): ip_version = common_utils.get_ip_version(cidr) self._as_root([ip_version], ('del', cidr, 'dev', self.name))
def fdb_ip_entry_exists(mac, ip, interface): ip_version = utils.get_ip_version(ip) entry = ip_lib.dump_neigh_entries(ip_version, interface, dst=ip, lladdr=mac) return entry != []