prompt: 
  We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Implement filter 'route.vpc-peering-connection-id' for DescribeRouteTables
  Hi, when I try to mock the DescribeRouteTables I got the following error.
  
  `FilterNotImplementedError: The filter 'route.vpc-peering-connection-id' for DescribeRouteTables has not been implemented in Moto yet. Feel free to open an issue at https://github.com/spulec/moto/issues
  `
  
  It would be nice to add this filter to moto, thanks!
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  
  --- BEGIN FILE ---
  ```
  ### moto/ec2/models/route_tables.py
  import ipaddress
  
  from moto.core import CloudFormationModel
  from .core import TaggedEC2Resource
  from ..exceptions import (
      DependencyViolationError,
      InvalidRouteError,
      InvalidRouteTableIdError,
      InvalidAssociationIdError,
      InvalidDestinationCIDRBlockParameterError,
      RouteAlreadyExistsError,
  )
  from ..utils import (
      EC2_RESOURCE_TO_PREFIX,
      generate_route_id,
      generic_filter,
      random_subnet_association_id,
      random_route_table_id,
      split_route_id,
  )
  
  
  class RouteTable(TaggedEC2Resource, CloudFormationModel):
      def __init__(self, ec2_backend, route_table_id, vpc_id, main=False):
          self.ec2_backend = ec2_backend
          self.id = route_table_id
          self.vpc_id = vpc_id
          if main:
              self.main_association_id = random_subnet_association_id()
          else:
              self.main_association_id = None
          self.associations = {}
          self.routes = {}
  
      @property
      def owner_id(self):
          return self.ec2_backend.account_id
  
      @staticmethod
      def cloudformation_name_type():
          return None
  
      @staticmethod
      def cloudformation_type():
          # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html
          return "AWS::EC2::RouteTable"
  
      @classmethod
      def create_from_cloudformation_json(
          cls, resource_name, cloudformation_json, account_id, region_name, **kwargs
      ):
          from ..models import ec2_backends
  
          properties = cloudformation_json["Properties"]
  
          vpc_id = properties["VpcId"]
          ec2_backend = ec2_backends[account_id][region_name]
          route_table = ec2_backend.create_route_table(vpc_id=vpc_id)
          return route_table
  
      @property
      def physical_resource_id(self):
          return self.id
  
      def get_filter_value(self, filter_name):
          if filter_name == "association.main":
              # Note: Boto only supports 'true'.
              # https://github.com/boto/boto/issues/1742
              if self.main_association_id is not None:
                  return "true"
              else:
                  return "false"
          elif filter_name == "route-table-id":
              return self.id
          elif filter_name == "vpc-id":
              return self.vpc_id
          elif filter_name == "association.route-table-id":
              return self.id
          elif filter_name == "association.route-table-association-id":
              return self.all_associations_ids
          elif filter_name == "association.subnet-id":
              return self.associations.values()
          elif filter_name == "route.gateway-id":
              return [
                  route.gateway.id
                  for route in self.routes.values()
                  if route.gateway is not None
              ]
          else:
              return super().get_filter_value(filter_name, "DescribeRouteTables")
  
      @property
      def all_associations_ids(self):
          # NOTE(yoctozepto): Doing an explicit copy to not touch the original.
          all_associations = set(self.associations)
          if self.main_association_id is not None:
              all_associations.add(self.main_association_id)
          return all_associations
  
  
  class RouteTableBackend:
      def __init__(self):
          self.route_tables = {}
  
      def create_route_table(self, vpc_id, tags=None, main=False):
          route_table_id = random_route_table_id()
          vpc = self.get_vpc(vpc_id)  # Validate VPC exists
          route_table = RouteTable(self, route_table_id, vpc_id, main=main)
          for tag in tags or []:
              route_table.add_tag(tag.get("Key"), tag.get("Value"))
          self.route_tables[route_table_id] = route_table
  
          # creating default routes for ipv4 cirds
          ipv4_cidrs = vpc.get_cidr_block_association_set(ipv6=False)
          for ipv4_cidr in ipv4_cidrs:
              self.create_route(route_table_id, ipv4_cidr.get("cidr_block"), local=True)
  
          # creating default routes for ipv6 cidrs
          ipv6_cidrs = vpc.get_cidr_block_association_set(ipv6=True)
          for ipv6_cidr in ipv6_cidrs:
              self.create_route(
                  route_table_id,
                  destination_cidr_block=None,
                  local=True,
                  destination_ipv6_cidr_block=ipv6_cidr.get("cidr_block"),
              )
  
          return route_table
  
      def get_route_table(self, route_table_id):
          route_table = self.route_tables.get(route_table_id, None)
          if not route_table:
              raise InvalidRouteTableIdError(route_table_id)
          return route_table
  
      def describe_route_tables(self, route_table_ids=None, filters=None):
          route_tables = self.route_tables.copy().values()
  
          if route_table_ids:
              route_tables = [
                  route_table
                  for route_table in route_tables
                  if route_table.id in route_table_ids
              ]
              if len(route_tables) != len(route_table_ids):
                  invalid_id = list(
                      set(route_table_ids).difference(
                          set([route_table.id for route_table in route_tables])
                      )
                  )[0]
                  raise InvalidRouteTableIdError(invalid_id)
  
          return generic_filter(filters, route_tables)
  
      def delete_route_table(self, route_table_id):
          route_table = self.get_route_table(route_table_id)
          if route_table.associations:
              raise DependencyViolationError(
                  "The routeTable '{0}' has dependencies and cannot be deleted.".format(
                      route_table_id
                  )
              )
          self.route_tables.pop(route_table_id)
          return True
  
      def associate_route_table(self, route_table_id, gateway_id=None, subnet_id=None):
          # Idempotent if association already exists.
          route_tables_by_subnet = self.describe_route_tables(
              filters={"association.subnet-id": [subnet_id]}
          )
          if route_tables_by_subnet:
              for association_id, check_subnet_id in route_tables_by_subnet[
                  0
              ].associations.items():
                  if subnet_id == check_subnet_id:
                      return association_id
  
          # Association does not yet exist, so create it.
          route_table = self.get_route_table(route_table_id)
          if gateway_id is None:
              self.get_subnet(subnet_id)  # Validate subnet exists
              association_id = random_subnet_association_id()
              route_table.associations[association_id] = subnet_id
              return association_id
          if subnet_id is None:
              association_id = random_subnet_association_id()
              route_table.associations[association_id] = gateway_id
              return association_id
  
      def disassociate_route_table(self, association_id):
          for route_table in self.route_tables.values():
              if association_id in route_table.associations:
                  return route_table.associations.pop(association_id, None)
          raise InvalidAssociationIdError(association_id)
  
      def replace_route_table_association(self, association_id, route_table_id):
          # Idempotent if association already exists.
          new_route_table = self.get_route_table(route_table_id)
          if association_id in new_route_table.all_associations_ids:
              return association_id
  
          # Find route table which currently has the association, error if none.
          route_tables_by_association_id = self.describe_route_tables(
              filters={"association.route-table-association-id": [association_id]}
          )
          if not route_tables_by_association_id:
              raise InvalidAssociationIdError(association_id)
          previous_route_table = route_tables_by_association_id[0]
  
          # Remove existing association, create new one.
          new_association_id = random_subnet_association_id()
          if previous_route_table.main_association_id == association_id:
              previous_route_table.main_association_id = None
              new_route_table.main_association_id = new_association_id
          else:
              association_target_id = previous_route_table.associations.pop(
                  association_id
              )
              new_route_table.associations[new_association_id] = association_target_id
          return new_association_id
  
  
  # TODO: refractor to isloate class methods from backend logic
  class Route(CloudFormationModel):
      def __init__(
          self,
          route_table,
          destination_cidr_block,
          destination_ipv6_cidr_block,
          destination_prefix_list=None,
          local=False,
          gateway=None,
          instance=None,
          nat_gateway=None,
          egress_only_igw=None,
          transit_gateway=None,
          interface=None,
          vpc_pcx=None,
          carrier_gateway=None,
      ):
          self.id = generate_route_id(
              route_table.id,
              destination_cidr_block,
              destination_ipv6_cidr_block,
              destination_prefix_list.id if destination_prefix_list else None,
          )
          self.route_table = route_table
          self.destination_cidr_block = destination_cidr_block
          self.destination_ipv6_cidr_block = destination_ipv6_cidr_block
          self.destination_prefix_list = destination_prefix_list
          self.local = local
          self.gateway = gateway
          self.instance = instance
          self.nat_gateway = nat_gateway
          self.egress_only_igw = egress_only_igw
          self.transit_gateway = transit_gateway
          self.interface = interface
          self.vpc_pcx = vpc_pcx
          self.carrier_gateway = carrier_gateway
  
      @property
      def physical_resource_id(self):
          return self.id
  
      @staticmethod
      def cloudformation_name_type():
          return None
  
      @staticmethod
      def cloudformation_type():
          # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route.html
          return "AWS::EC2::Route"
  
      @classmethod
      def create_from_cloudformation_json(
          cls, resource_name, cloudformation_json, account_id, region_name, **kwargs
      ):
          from ..models import ec2_backends
  
          properties = cloudformation_json["Properties"]
  
          gateway_id = properties.get("GatewayId")
          instance_id = properties.get("InstanceId")
          interface_id = properties.get("NetworkInterfaceId")
          nat_gateway_id = properties.get("NatGatewayId")
          egress_only_igw_id = properties.get("EgressOnlyInternetGatewayId")
          transit_gateway_id = properties.get("TransitGatewayId")
          pcx_id = properties.get("VpcPeeringConnectionId")
  
          route_table_id = properties["RouteTableId"]
          ec2_backend = ec2_backends[account_id][region_name]
          route_table = ec2_backend.create_route(
              route_table_id=route_table_id,
              destination_cidr_block=properties.get("DestinationCidrBlock"),
              gateway_id=gateway_id,
              instance_id=instance_id,
              nat_gateway_id=nat_gateway_id,
              egress_only_igw_id=egress_only_igw_id,
              transit_gateway_id=transit_gateway_id,
              interface_id=interface_id,
              vpc_peering_connection_id=pcx_id,
          )
          return route_table
  
  
  class RouteBackend:
      def create_route(
          self,
          route_table_id,
          destination_cidr_block,
          destination_ipv6_cidr_block=None,
          destination_prefix_list_id=None,
          local=False,
          gateway_id=None,
          instance_id=None,
          nat_gateway_id=None,
          egress_only_igw_id=None,
          transit_gateway_id=None,
          interface_id=None,
          vpc_peering_connection_id=None,
          carrier_gateway_id=None,
      ):
          gateway = None
          nat_gateway = None
          transit_gateway = None
          egress_only_igw = None
          interface = None
          destination_prefix_list = None
          carrier_gateway = None
  
          route_table = self.get_route_table(route_table_id)
  
          if interface_id:
              # for validating interface Id whether it is valid or not.
              interface = self.get_network_interface(interface_id)
  
          else:
              if gateway_id:
                  if EC2_RESOURCE_TO_PREFIX["vpn-gateway"] in gateway_id:
                      gateway = self.get_vpn_gateway(gateway_id)
                  elif EC2_RESOURCE_TO_PREFIX["internet-gateway"] in gateway_id:
                      gateway = self.get_internet_gateway(gateway_id)
                  elif EC2_RESOURCE_TO_PREFIX["vpc-endpoint"] in gateway_id:
                      gateway = self.get_vpc_end_point(gateway_id)
  
              if destination_cidr_block:
                  self.__validate_destination_cidr_block(
                      destination_cidr_block, route_table
                  )
  
              if nat_gateway_id is not None:
                  nat_gateway = self.nat_gateways.get(nat_gateway_id)
              if egress_only_igw_id is not None:
                  egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)
              if transit_gateway_id is not None:
                  transit_gateway = self.transit_gateways.get(transit_gateway_id)
              if destination_prefix_list_id is not None:
                  destination_prefix_list = self.managed_prefix_lists.get(
                      destination_prefix_list_id
                  )
              if carrier_gateway_id is not None:
                  carrier_gateway = self.carrier_gateways.get(carrier_gateway_id)
  
          route = Route(
              route_table,
              destination_cidr_block,
              destination_ipv6_cidr_block,
              destination_prefix_list,
              local=local,
              gateway=gateway,
              instance=self.get_instance(instance_id) if instance_id else None,
              nat_gateway=nat_gateway,
              egress_only_igw=egress_only_igw,
              transit_gateway=transit_gateway,
              interface=interface,
              carrier_gateway=carrier_gateway,
              vpc_pcx=self.get_vpc_peering_connection(vpc_peering_connection_id)
              if vpc_peering_connection_id
              else None,
          )
          route_table.routes[route.id] = route
          return route
  
      def replace_route(
          self,
          route_table_id,
          destination_cidr_block,
          destination_ipv6_cidr_block=None,
          destination_prefix_list_id=None,
          nat_gateway_id=None,
          egress_only_igw_id=None,
          transit_gateway_id=None,
          gateway_id=None,
          instance_id=None,
          interface_id=None,
          vpc_peering_connection_id=None,
      ):
          route_table = self.get_route_table(route_table_id)
          route_id = generate_route_id(
              route_table.id, destination_cidr_block, destination_ipv6_cidr_block
          )
          route = route_table.routes[route_id]
  
          if interface_id:
              self.raise_not_implemented_error("ReplaceRoute to NetworkInterfaceId")
  
          route.gateway = None
          route.nat_gateway = None
          route.egress_only_igw = None
          route.transit_gateway = None
          if gateway_id:
              if EC2_RESOURCE_TO_PREFIX["vpn-gateway"] in gateway_id:
                  route.gateway = self.get_vpn_gateway(gateway_id)
              elif EC2_RESOURCE_TO_PREFIX["internet-gateway"] in gateway_id:
                  route.gateway = self.get_internet_gateway(gateway_id)
  
          if nat_gateway_id is not None:
              route.nat_gateway = self.nat_gateways.get(nat_gateway_id)
          if egress_only_igw_id is not None:
              route.egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)
          if transit_gateway_id is not None:
              route.transit_gateway = self.transit_gateways.get(transit_gateway_id)
          if destination_prefix_list_id is not None:
              route.prefix_list = self.managed_prefix_lists.get(
                  destination_prefix_list_id
              )
  
          route.instance = self.get_instance(instance_id) if instance_id else None
          route.interface = None
          route.vpc_pcx = (
              self.get_vpc_peering_connection(vpc_peering_connection_id)
              if vpc_peering_connection_id
              else None
          )
  
          route_table.routes[route.id] = route
          return route
  
      def get_route(self, route_id):
          route_table_id, _ = split_route_id(route_id)
          route_table = self.get_route_table(route_table_id)
          return route_table.get(route_id)
  
      def delete_route(
          self,
          route_table_id,
          destination_cidr_block,
          destination_ipv6_cidr_block=None,
          destination_prefix_list_id=None,
      ):
          cidr = destination_cidr_block
          route_table = self.get_route_table(route_table_id)
          if destination_ipv6_cidr_block:
              cidr = destination_ipv6_cidr_block
          if destination_prefix_list_id:
              cidr = destination_prefix_list_id
          route_id = generate_route_id(route_table_id, cidr)
          deleted = route_table.routes.pop(route_id, None)
          if not deleted:
              raise InvalidRouteError(route_table_id, cidr)
          return deleted
  
      def __validate_destination_cidr_block(self, destination_cidr_block, route_table):
          """
          Utility function to check the destination CIDR block
          Will validate the format and check for overlap with existing routes
          """
          try:
              ip_v4_network = ipaddress.IPv4Network(
                  str(destination_cidr_block), strict=False
              )
          except ValueError:
              raise InvalidDestinationCIDRBlockParameterError(destination_cidr_block)
  
          if not route_table.routes:
              return
          for route in route_table.routes.values():
              if not route.destination_cidr_block:
                  continue
              if not route.local and ip_v4_network.overlaps(
                  ipaddress.IPv4Network(str(route.destination_cidr_block))
              ):
                  raise RouteAlreadyExistsError(destination_cidr_block)
  
  ```
  --- END FILE ---
  
  Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.
  
  Every *SEARCH/REPLACE* edit must use this format:
  1. The file path
  2. The start of search block: <<<<<<< SEARCH
  3. A contiguous chunk of lines to search for in the existing source code
  4. The dividing line: =======
  5. The lines to replace into the source code
  6. The end of the replace block: >>>>>>> REPLACE
  
  Here is an example:
  
  ```python
  ### mathweb/flask/app.py
  <<<<<<< SEARCH
  from flask import Flask
  =======
  import math
  from flask import Flask
  >>>>>>> REPLACE
  ```
  
  Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
  Wrap the *SEARCH/REPLACE* edit in blocks ```python...```.
  
instance: {"FAIL_TO_PASS": ["tests/test_ec2/test_route_tables.py::test_route_tables_filters_vpc_peering_connection"], "PASS_TO_PASS": ["tests/test_ec2/test_route_tables.py::test_route_table_associations", "tests/test_ec2/test_route_tables.py::test_route_tables_defaults", "tests/test_ec2/test_route_tables.py::test_route_tables_filters_standard", "tests/test_ec2/test_route_tables.py::test_routes_vpn_gateway", "tests/test_ec2/test_route_tables.py::test_create_route_with_network_interface_id", "tests/test_ec2/test_route_tables.py::test_route_table_replace_route_table_association_for_main", "tests/test_ec2/test_route_tables.py::test_route_tables_additional", "tests/test_ec2/test_route_tables.py::test_routes_already_exist", "tests/test_ec2/test_route_tables.py::test_network_acl_tagging", "tests/test_ec2/test_route_tables.py::test_create_route_with_egress_only_igw", "tests/test_ec2/test_route_tables.py::test_create_vpc_end_point", "tests/test_ec2/test_route_tables.py::test_create_route_with_unknown_egress_only_igw", "tests/test_ec2/test_route_tables.py::test_routes_replace", "tests/test_ec2/test_route_tables.py::test_create_route_with_invalid_destination_cidr_block_parameter", "tests/test_ec2/test_route_tables.py::test_describe_route_tables_with_nat_gateway", "tests/test_ec2/test_route_tables.py::test_create_route_tables_with_tags", "tests/test_ec2/test_route_tables.py::test_route_tables_filters_associations", "tests/test_ec2/test_route_tables.py::test_routes_vpc_peering_connection", "tests/test_ec2/test_route_tables.py::test_associate_route_table_by_gateway", "tests/test_ec2/test_route_tables.py::test_routes_not_supported", "tests/test_ec2/test_route_tables.py::test_route_table_replace_route_table_association", "tests/test_ec2/test_route_tables.py::test_routes_additional", "tests/test_ec2/test_route_tables.py::test_route_table_get_by_tag", "tests/test_ec2/test_route_tables.py::test_associate_route_table_by_subnet"], "base_commit": "c0b581aa08b234ed036c43901cee84cc9e955fa4", "created_at": "2022-10-26 07:35:46", "hints_text": "", "instance_id": "getmoto__moto-5601", "patch": "diff --git a/moto/ec2/models/route_tables.py b/moto/ec2/models/route_tables.py\n--- a/moto/ec2/models/route_tables.py\n+++ b/moto/ec2/models/route_tables.py\n@@ -86,6 +86,12 @@ def get_filter_value(self, filter_name):\n                 for route in self.routes.values()\n                 if route.gateway is not None\n             ]\n+        elif filter_name == \"route.vpc-peering-connection-id\":\n+            return [\n+                route.vpc_pcx.id\n+                for route in self.routes.values()\n+                if route.vpc_pcx is not None\n+            ]\n         else:\n             return super().get_filter_value(filter_name, \"DescribeRouteTables\")\n \n", "problem_statement": "Implement filter 'route.vpc-peering-connection-id' for DescribeRouteTables\nHi, when I try to mock the DescribeRouteTables I got the following error.\r\n\r\n`FilterNotImplementedError: The filter 'route.vpc-peering-connection-id' for DescribeRouteTables has not been implemented in Moto yet. Feel free to open an issue at https://github.com/spulec/moto/issues\r\n`\r\n\r\nIt would be nice to add this filter to moto, thanks!\n", "repo": "getmoto/moto", "test_patch": "diff --git a/tests/test_ec2/test_route_tables.py b/tests/test_ec2/test_route_tables.py\n--- a/tests/test_ec2/test_route_tables.py\n+++ b/tests/test_ec2/test_route_tables.py\n@@ -204,6 +204,58 @@ def test_route_tables_filters_associations():\n     subnet_route_tables[0][\"Associations\"].should.have.length_of(2)\n \n \n+@mock_ec2\n+def test_route_tables_filters_vpc_peering_connection():\n+    client = boto3.client(\"ec2\", region_name=\"us-east-1\")\n+    ec2 = boto3.resource(\"ec2\", region_name=\"us-east-1\")\n+    vpc = ec2.create_vpc(CidrBlock=\"10.0.0.0/16\")\n+    main_route_table_id = client.describe_route_tables(\n+        Filters=[\n+            {\"Name\": \"vpc-id\", \"Values\": [vpc.id]},\n+            {\"Name\": \"association.main\", \"Values\": [\"true\"]},\n+        ]\n+    )[\"RouteTables\"][0][\"RouteTableId\"]\n+    main_route_table = ec2.RouteTable(main_route_table_id)\n+    ROUTE_CIDR = \"10.0.0.4/24\"\n+\n+    peer_vpc = ec2.create_vpc(CidrBlock=\"11.0.0.0/16\")\n+    vpc_pcx = ec2.create_vpc_peering_connection(VpcId=vpc.id, PeerVpcId=peer_vpc.id)\n+\n+    main_route_table.create_route(\n+        DestinationCidrBlock=ROUTE_CIDR, VpcPeeringConnectionId=vpc_pcx.id\n+    )\n+\n+    # Refresh route table\n+    main_route_table.reload()\n+    new_routes = [\n+        route\n+        for route in main_route_table.routes\n+        if route.destination_cidr_block != vpc.cidr_block\n+    ]\n+    new_routes.should.have.length_of(1)\n+\n+    new_route = new_routes[0]\n+    new_route.gateway_id.should.equal(None)\n+    new_route.instance_id.should.equal(None)\n+    new_route.vpc_peering_connection_id.should.equal(vpc_pcx.id)\n+    new_route.state.should.equal(\"active\")\n+    new_route.destination_cidr_block.should.equal(ROUTE_CIDR)\n+\n+    # Filter by Peering Connection\n+    route_tables = client.describe_route_tables(\n+        Filters=[{\"Name\": \"route.vpc-peering-connection-id\", \"Values\": [vpc_pcx.id]}]\n+    )[\"RouteTables\"]\n+    route_tables.should.have.length_of(1)\n+    route_table = route_tables[0]\n+    route_table[\"RouteTableId\"].should.equal(main_route_table_id)\n+    vpc_pcx_ids = [\n+        route[\"VpcPeeringConnectionId\"]\n+        for route in route_table[\"Routes\"]\n+        if \"VpcPeeringConnectionId\" in route\n+    ]\n+    all(vpc_pcx_id == vpc_pcx.id for vpc_pcx_id in vpc_pcx_ids)\n+\n+\n @mock_ec2\n def test_route_table_associations():\n     client = boto3.client(\"ec2\", region_name=\"us-east-1\")\n", "version": "4.0"}
parsed_commit_content: {"file_diffs":[{"old_file_content":"import ipaddress\n\nfrom moto.core import CloudFormationModel\nfrom .core import TaggedEC2Resource\nfrom ..exceptions import (\n    DependencyViolationError,\n    InvalidRouteError,\n    InvalidRouteTableIdError,\n    InvalidAssociationIdError,\n    InvalidDestinationCIDRBlockParameterError,\n    RouteAlreadyExistsError,\n)\nfrom ..utils import (\n    EC2_RESOURCE_TO_PREFIX,\n    generate_route_id,\n    generic_filter,\n    random_subnet_association_id,\n    random_route_table_id,\n    split_route_id,\n)\n\n\nclass RouteTable(TaggedEC2Resource, CloudFormationModel):\n    def __init__(self, ec2_backend, route_table_id, vpc_id, main=False):\n        self.ec2_backend = ec2_backend\n        self.id = route_table_id\n        self.vpc_id = vpc_id\n        if main:\n            self.main_association_id = random_subnet_association_id()\n        else:\n            self.main_association_id = None\n        self.associations = {}\n        self.routes = {}\n\n    @property\n    def owner_id(self):\n        return self.ec2_backend.account_id\n\n    @staticmethod\n    def cloudformation_name_type():\n        return None\n\n    @staticmethod\n    def cloudformation_type():\n        # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html\n        return \"AWS::EC2::RouteTable\"\n\n    @classmethod\n    def create_from_cloudformation_json(\n        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs\n    ):\n        from ..models import ec2_backends\n\n        properties = cloudformation_json[\"Properties\"]\n\n        vpc_id = properties[\"VpcId\"]\n        ec2_backend = ec2_backends[account_id][region_name]\n        route_table = ec2_backend.create_route_table(vpc_id=vpc_id)\n        return route_table\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    def get_filter_value(self, filter_name):\n        if filter_name == \"association.main\":\n            # Note: Boto only supports 'true'.\n            # https://github.com/boto/boto/issues/1742\n            if self.main_association_id is not None:\n                return \"true\"\n            else:\n                return \"false\"\n        elif filter_name == \"route-table-id\":\n            return self.id\n        elif filter_name == \"vpc-id\":\n            return self.vpc_id\n        elif filter_name == \"association.route-table-id\":\n            return self.id\n        elif filter_name == \"association.route-table-association-id\":\n            return self.all_associations_ids\n        elif filter_name == \"association.subnet-id\":\n            return self.associations.values()\n        elif filter_name == \"route.gateway-id\":\n            return [\n                route.gateway.id\n                for route in self.routes.values()\n                if route.gateway is not None\n            ]\n        else:\n            return super().get_filter_value(filter_name, \"DescribeRouteTables\")\n\n    @property\n    def all_associations_ids(self):\n        # NOTE(yoctozepto): Doing an explicit copy to not touch the original.\n        all_associations = set(self.associations)\n        if self.main_association_id is not None:\n            all_associations.add(self.main_association_id)\n        return all_associations\n\n\nclass RouteTableBackend:\n    def __init__(self):\n        self.route_tables = {}\n\n    def create_route_table(self, vpc_id, tags=None, main=False):\n        route_table_id = random_route_table_id()\n        vpc = self.get_vpc(vpc_id)  # Validate VPC exists\n        route_table = RouteTable(self, route_table_id, vpc_id, main=main)\n        for tag in tags or []:\n            route_table.add_tag(tag.get(\"Key\"), tag.get(\"Value\"))\n        self.route_tables[route_table_id] = route_table\n\n        # creating default routes for ipv4 cirds\n        ipv4_cidrs = vpc.get_cidr_block_association_set(ipv6=False)\n        for ipv4_cidr in ipv4_cidrs:\n            self.create_route(route_table_id, ipv4_cidr.get(\"cidr_block\"), local=True)\n\n        # creating default routes for ipv6 cidrs\n        ipv6_cidrs = vpc.get_cidr_block_association_set(ipv6=True)\n        for ipv6_cidr in ipv6_cidrs:\n            self.create_route(\n                route_table_id,\n                destination_cidr_block=None,\n                local=True,\n                destination_ipv6_cidr_block=ipv6_cidr.get(\"cidr_block\"),\n            )\n\n        return route_table\n\n    def get_route_table(self, route_table_id):\n        route_table = self.route_tables.get(route_table_id, None)\n        if not route_table:\n            raise InvalidRouteTableIdError(route_table_id)\n        return route_table\n\n    def describe_route_tables(self, route_table_ids=None, filters=None):\n        route_tables = self.route_tables.copy().values()\n\n        if route_table_ids:\n            route_tables = [\n                route_table\n                for route_table in route_tables\n                if route_table.id in route_table_ids\n            ]\n            if len(route_tables) != len(route_table_ids):\n                invalid_id = list(\n                    set(route_table_ids).difference(\n                        set([route_table.id for route_table in route_tables])\n                    )\n                )[0]\n                raise InvalidRouteTableIdError(invalid_id)\n\n        return generic_filter(filters, route_tables)\n\n    def delete_route_table(self, route_table_id):\n        route_table = self.get_route_table(route_table_id)\n        if route_table.associations:\n            raise DependencyViolationError(\n                \"The routeTable '{0}' has dependencies and cannot be deleted.\".format(\n                    route_table_id\n                )\n            )\n        self.route_tables.pop(route_table_id)\n        return True\n\n    def associate_route_table(self, route_table_id, gateway_id=None, subnet_id=None):\n        # Idempotent if association already exists.\n        route_tables_by_subnet = self.describe_route_tables(\n            filters={\"association.subnet-id\": [subnet_id]}\n        )\n        if route_tables_by_subnet:\n            for association_id, check_subnet_id in route_tables_by_subnet[\n                0\n            ].associations.items():\n                if subnet_id == check_subnet_id:\n                    return association_id\n\n        # Association does not yet exist, so create it.\n        route_table = self.get_route_table(route_table_id)\n        if gateway_id is None:\n            self.get_subnet(subnet_id)  # Validate subnet exists\n            association_id = random_subnet_association_id()\n            route_table.associations[association_id] = subnet_id\n            return association_id\n        if subnet_id is None:\n            association_id = random_subnet_association_id()\n            route_table.associations[association_id] = gateway_id\n            return association_id\n\n    def disassociate_route_table(self, association_id):\n        for route_table in self.route_tables.values():\n            if association_id in route_table.associations:\n                return route_table.associations.pop(association_id, None)\n        raise InvalidAssociationIdError(association_id)\n\n    def replace_route_table_association(self, association_id, route_table_id):\n        # Idempotent if association already exists.\n        new_route_table = self.get_route_table(route_table_id)\n        if association_id in new_route_table.all_associations_ids:\n            return association_id\n\n        # Find route table which currently has the association, error if none.\n        route_tables_by_association_id = self.describe_route_tables(\n            filters={\"association.route-table-association-id\": [association_id]}\n        )\n        if not route_tables_by_association_id:\n            raise InvalidAssociationIdError(association_id)\n        previous_route_table = route_tables_by_association_id[0]\n\n        # Remove existing association, create new one.\n        new_association_id = random_subnet_association_id()\n        if previous_route_table.main_association_id == association_id:\n            previous_route_table.main_association_id = None\n            new_route_table.main_association_id = new_association_id\n        else:\n            association_target_id = previous_route_table.associations.pop(\n                association_id\n            )\n            new_route_table.associations[new_association_id] = association_target_id\n        return new_association_id\n\n\n# TODO: refractor to isloate class methods from backend logic\nclass Route(CloudFormationModel):\n    def __init__(\n        self,\n        route_table,\n        destination_cidr_block,\n        destination_ipv6_cidr_block,\n        destination_prefix_list=None,\n        local=False,\n        gateway=None,\n        instance=None,\n        nat_gateway=None,\n        egress_only_igw=None,\n        transit_gateway=None,\n        interface=None,\n        vpc_pcx=None,\n        carrier_gateway=None,\n    ):\n        self.id = generate_route_id(\n            route_table.id,\n            destination_cidr_block,\n            destination_ipv6_cidr_block,\n            destination_prefix_list.id if destination_prefix_list else None,\n        )\n        self.route_table = route_table\n        self.destination_cidr_block = destination_cidr_block\n        self.destination_ipv6_cidr_block = destination_ipv6_cidr_block\n        self.destination_prefix_list = destination_prefix_list\n        self.local = local\n        self.gateway = gateway\n        self.instance = instance\n        self.nat_gateway = nat_gateway\n        self.egress_only_igw = egress_only_igw\n        self.transit_gateway = transit_gateway\n        self.interface = interface\n        self.vpc_pcx = vpc_pcx\n        self.carrier_gateway = carrier_gateway\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    @staticmethod\n    def cloudformation_name_type():\n        return None\n\n    @staticmethod\n    def cloudformation_type():\n        # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route.html\n        return \"AWS::EC2::Route\"\n\n    @classmethod\n    def create_from_cloudformation_json(\n        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs\n    ):\n        from ..models import ec2_backends\n\n        properties = cloudformation_json[\"Properties\"]\n\n        gateway_id = properties.get(\"GatewayId\")\n        instance_id = properties.get(\"InstanceId\")\n        interface_id = properties.get(\"NetworkInterfaceId\")\n        nat_gateway_id = properties.get(\"NatGatewayId\")\n        egress_only_igw_id = properties.get(\"EgressOnlyInternetGatewayId\")\n        transit_gateway_id = properties.get(\"TransitGatewayId\")\n        pcx_id = properties.get(\"VpcPeeringConnectionId\")\n\n        route_table_id = properties[\"RouteTableId\"]\n        ec2_backend = ec2_backends[account_id][region_name]\n        route_table = ec2_backend.create_route(\n            route_table_id=route_table_id,\n            destination_cidr_block=properties.get(\"DestinationCidrBlock\"),\n            gateway_id=gateway_id,\n            instance_id=instance_id,\n            nat_gateway_id=nat_gateway_id,\n            egress_only_igw_id=egress_only_igw_id,\n            transit_gateway_id=transit_gateway_id,\n            interface_id=interface_id,\n            vpc_peering_connection_id=pcx_id,\n        )\n        return route_table\n\n\nclass RouteBackend:\n    def create_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n        local=False,\n        gateway_id=None,\n        instance_id=None,\n        nat_gateway_id=None,\n        egress_only_igw_id=None,\n        transit_gateway_id=None,\n        interface_id=None,\n        vpc_peering_connection_id=None,\n        carrier_gateway_id=None,\n    ):\n        gateway = None\n        nat_gateway = None\n        transit_gateway = None\n        egress_only_igw = None\n        interface = None\n        destination_prefix_list = None\n        carrier_gateway = None\n\n        route_table = self.get_route_table(route_table_id)\n\n        if interface_id:\n            # for validating interface Id whether it is valid or not.\n            interface = self.get_network_interface(interface_id)\n\n        else:\n            if gateway_id:\n                if EC2_RESOURCE_TO_PREFIX[\"vpn-gateway\"] in gateway_id:\n                    gateway = self.get_vpn_gateway(gateway_id)\n                elif EC2_RESOURCE_TO_PREFIX[\"internet-gateway\"] in gateway_id:\n                    gateway = self.get_internet_gateway(gateway_id)\n                elif EC2_RESOURCE_TO_PREFIX[\"vpc-endpoint\"] in gateway_id:\n                    gateway = self.get_vpc_end_point(gateway_id)\n\n            if destination_cidr_block:\n                self.__validate_destination_cidr_block(\n                    destination_cidr_block, route_table\n                )\n\n            if nat_gateway_id is not None:\n                nat_gateway = self.nat_gateways.get(nat_gateway_id)\n            if egress_only_igw_id is not None:\n                egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)\n            if transit_gateway_id is not None:\n                transit_gateway = self.transit_gateways.get(transit_gateway_id)\n            if destination_prefix_list_id is not None:\n                destination_prefix_list = self.managed_prefix_lists.get(\n                    destination_prefix_list_id\n                )\n            if carrier_gateway_id is not None:\n                carrier_gateway = self.carrier_gateways.get(carrier_gateway_id)\n\n        route = Route(\n            route_table,\n            destination_cidr_block,\n            destination_ipv6_cidr_block,\n            destination_prefix_list,\n            local=local,\n            gateway=gateway,\n            instance=self.get_instance(instance_id) if instance_id else None,\n            nat_gateway=nat_gateway,\n            egress_only_igw=egress_only_igw,\n            transit_gateway=transit_gateway,\n            interface=interface,\n            carrier_gateway=carrier_gateway,\n            vpc_pcx=self.get_vpc_peering_connection(vpc_peering_connection_id)\n            if vpc_peering_connection_id\n            else None,\n        )\n        route_table.routes[route.id] = route\n        return route\n\n    def replace_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n        nat_gateway_id=None,\n        egress_only_igw_id=None,\n        transit_gateway_id=None,\n        gateway_id=None,\n        instance_id=None,\n        interface_id=None,\n        vpc_peering_connection_id=None,\n    ):\n        route_table = self.get_route_table(route_table_id)\n        route_id = generate_route_id(\n            route_table.id, destination_cidr_block, destination_ipv6_cidr_block\n        )\n        route = route_table.routes[route_id]\n\n        if interface_id:\n            self.raise_not_implemented_error(\"ReplaceRoute to NetworkInterfaceId\")\n\n        route.gateway = None\n        route.nat_gateway = None\n        route.egress_only_igw = None\n        route.transit_gateway = None\n        if gateway_id:\n            if EC2_RESOURCE_TO_PREFIX[\"vpn-gateway\"] in gateway_id:\n                route.gateway = self.get_vpn_gateway(gateway_id)\n            elif EC2_RESOURCE_TO_PREFIX[\"internet-gateway\"] in gateway_id:\n                route.gateway = self.get_internet_gateway(gateway_id)\n\n        if nat_gateway_id is not None:\n            route.nat_gateway = self.nat_gateways.get(nat_gateway_id)\n        if egress_only_igw_id is not None:\n            route.egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)\n        if transit_gateway_id is not None:\n            route.transit_gateway = self.transit_gateways.get(transit_gateway_id)\n        if destination_prefix_list_id is not None:\n            route.prefix_list = self.managed_prefix_lists.get(\n                destination_prefix_list_id\n            )\n\n        route.instance = self.get_instance(instance_id) if instance_id else None\n        route.interface = None\n        route.vpc_pcx = (\n            self.get_vpc_peering_connection(vpc_peering_connection_id)\n            if vpc_peering_connection_id\n            else None\n        )\n\n        route_table.routes[route.id] = route\n        return route\n\n    def get_route(self, route_id):\n        route_table_id, _ = split_route_id(route_id)\n        route_table = self.get_route_table(route_table_id)\n        return route_table.get(route_id)\n\n    def delete_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n    ):\n        cidr = destination_cidr_block\n        route_table = self.get_route_table(route_table_id)\n        if destination_ipv6_cidr_block:\n            cidr = destination_ipv6_cidr_block\n        if destination_prefix_list_id:\n            cidr = destination_prefix_list_id\n        route_id = generate_route_id(route_table_id, cidr)\n        deleted = route_table.routes.pop(route_id, None)\n        if not deleted:\n            raise InvalidRouteError(route_table_id, cidr)\n        return deleted\n\n    def __validate_destination_cidr_block(self, destination_cidr_block, route_table):\n        \"\"\"\n        Utility function to check the destination CIDR block\n        Will validate the format and check for overlap with existing routes\n        \"\"\"\n        try:\n            ip_v4_network = ipaddress.IPv4Network(\n                str(destination_cidr_block), strict=False\n            )\n        except ValueError:\n            raise InvalidDestinationCIDRBlockParameterError(destination_cidr_block)\n\n        if not route_table.routes:\n            return\n        for route in route_table.routes.values():\n            if not route.destination_cidr_block:\n                continue\n            if not route.local and ip_v4_network.overlaps(\n                ipaddress.IPv4Network(str(route.destination_cidr_block))\n            ):\n                raise RouteAlreadyExistsError(destination_cidr_block)\n","new_file_content":"import ipaddress\n\nfrom moto.core import CloudFormationModel\nfrom .core import TaggedEC2Resource\nfrom ..exceptions import (\n    DependencyViolationError,\n    InvalidRouteError,\n    InvalidRouteTableIdError,\n    InvalidAssociationIdError,\n    InvalidDestinationCIDRBlockParameterError,\n    RouteAlreadyExistsError,\n)\nfrom ..utils import (\n    EC2_RESOURCE_TO_PREFIX,\n    generate_route_id,\n    generic_filter,\n    random_subnet_association_id,\n    random_route_table_id,\n    split_route_id,\n)\n\n\nclass RouteTable(TaggedEC2Resource, CloudFormationModel):\n    def __init__(self, ec2_backend, route_table_id, vpc_id, main=False):\n        self.ec2_backend = ec2_backend\n        self.id = route_table_id\n        self.vpc_id = vpc_id\n        if main:\n            self.main_association_id = random_subnet_association_id()\n        else:\n            self.main_association_id = None\n        self.associations = {}\n        self.routes = {}\n\n    @property\n    def owner_id(self):\n        return self.ec2_backend.account_id\n\n    @staticmethod\n    def cloudformation_name_type():\n        return None\n\n    @staticmethod\n    def cloudformation_type():\n        # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html\n        return \"AWS::EC2::RouteTable\"\n\n    @classmethod\n    def create_from_cloudformation_json(\n        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs\n    ):\n        from ..models import ec2_backends\n\n        properties = cloudformation_json[\"Properties\"]\n\n        vpc_id = properties[\"VpcId\"]\n        ec2_backend = ec2_backends[account_id][region_name]\n        route_table = ec2_backend.create_route_table(vpc_id=vpc_id)\n        return route_table\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    def get_filter_value(self, filter_name):\n        if filter_name == \"association.main\":\n            # Note: Boto only supports 'true'.\n            # https://github.com/boto/boto/issues/1742\n            if self.main_association_id is not None:\n                return \"true\"\n            else:\n                return \"false\"\n        elif filter_name == \"route-table-id\":\n            return self.id\n        elif filter_name == \"vpc-id\":\n            return self.vpc_id\n        elif filter_name == \"association.route-table-id\":\n            return self.id\n        elif filter_name == \"association.route-table-association-id\":\n            return self.all_associations_ids\n        elif filter_name == \"association.subnet-id\":\n            return self.associations.values()\n        elif filter_name == \"route.gateway-id\":\n            return [\n                route.gateway.id\n                for route in self.routes.values()\n                if route.gateway is not None\n            ]\n        elif filter_name == \"route.vpc-peering-connection-id\":\n            return [\n                route.vpc_pcx.id\n                for route in self.routes.values()\n                if route.vpc_pcx is not None\n            ]\n        else:\n            return super().get_filter_value(filter_name, \"DescribeRouteTables\")\n\n    @property\n    def all_associations_ids(self):\n        # NOTE(yoctozepto): Doing an explicit copy to not touch the original.\n        all_associations = set(self.associations)\n        if self.main_association_id is not None:\n            all_associations.add(self.main_association_id)\n        return all_associations\n\n\nclass RouteTableBackend:\n    def __init__(self):\n        self.route_tables = {}\n\n    def create_route_table(self, vpc_id, tags=None, main=False):\n        route_table_id = random_route_table_id()\n        vpc = self.get_vpc(vpc_id)  # Validate VPC exists\n        route_table = RouteTable(self, route_table_id, vpc_id, main=main)\n        for tag in tags or []:\n            route_table.add_tag(tag.get(\"Key\"), tag.get(\"Value\"))\n        self.route_tables[route_table_id] = route_table\n\n        # creating default routes for ipv4 cirds\n        ipv4_cidrs = vpc.get_cidr_block_association_set(ipv6=False)\n        for ipv4_cidr in ipv4_cidrs:\n            self.create_route(route_table_id, ipv4_cidr.get(\"cidr_block\"), local=True)\n\n        # creating default routes for ipv6 cidrs\n        ipv6_cidrs = vpc.get_cidr_block_association_set(ipv6=True)\n        for ipv6_cidr in ipv6_cidrs:\n            self.create_route(\n                route_table_id,\n                destination_cidr_block=None,\n                local=True,\n                destination_ipv6_cidr_block=ipv6_cidr.get(\"cidr_block\"),\n            )\n\n        return route_table\n\n    def get_route_table(self, route_table_id):\n        route_table = self.route_tables.get(route_table_id, None)\n        if not route_table:\n            raise InvalidRouteTableIdError(route_table_id)\n        return route_table\n\n    def describe_route_tables(self, route_table_ids=None, filters=None):\n        route_tables = self.route_tables.copy().values()\n\n        if route_table_ids:\n            route_tables = [\n                route_table\n                for route_table in route_tables\n                if route_table.id in route_table_ids\n            ]\n            if len(route_tables) != len(route_table_ids):\n                invalid_id = list(\n                    set(route_table_ids).difference(\n                        set([route_table.id for route_table in route_tables])\n                    )\n                )[0]\n                raise InvalidRouteTableIdError(invalid_id)\n\n        return generic_filter(filters, route_tables)\n\n    def delete_route_table(self, route_table_id):\n        route_table = self.get_route_table(route_table_id)\n        if route_table.associations:\n            raise DependencyViolationError(\n                \"The routeTable '{0}' has dependencies and cannot be deleted.\".format(\n                    route_table_id\n                )\n            )\n        self.route_tables.pop(route_table_id)\n        return True\n\n    def associate_route_table(self, route_table_id, gateway_id=None, subnet_id=None):\n        # Idempotent if association already exists.\n        route_tables_by_subnet = self.describe_route_tables(\n            filters={\"association.subnet-id\": [subnet_id]}\n        )\n        if route_tables_by_subnet:\n            for association_id, check_subnet_id in route_tables_by_subnet[\n                0\n            ].associations.items():\n                if subnet_id == check_subnet_id:\n                    return association_id\n\n        # Association does not yet exist, so create it.\n        route_table = self.get_route_table(route_table_id)\n        if gateway_id is None:\n            self.get_subnet(subnet_id)  # Validate subnet exists\n            association_id = random_subnet_association_id()\n            route_table.associations[association_id] = subnet_id\n            return association_id\n        if subnet_id is None:\n            association_id = random_subnet_association_id()\n            route_table.associations[association_id] = gateway_id\n            return association_id\n\n    def disassociate_route_table(self, association_id):\n        for route_table in self.route_tables.values():\n            if association_id in route_table.associations:\n                return route_table.associations.pop(association_id, None)\n        raise InvalidAssociationIdError(association_id)\n\n    def replace_route_table_association(self, association_id, route_table_id):\n        # Idempotent if association already exists.\n        new_route_table = self.get_route_table(route_table_id)\n        if association_id in new_route_table.all_associations_ids:\n            return association_id\n\n        # Find route table which currently has the association, error if none.\n        route_tables_by_association_id = self.describe_route_tables(\n            filters={\"association.route-table-association-id\": [association_id]}\n        )\n        if not route_tables_by_association_id:\n            raise InvalidAssociationIdError(association_id)\n        previous_route_table = route_tables_by_association_id[0]\n\n        # Remove existing association, create new one.\n        new_association_id = random_subnet_association_id()\n        if previous_route_table.main_association_id == association_id:\n            previous_route_table.main_association_id = None\n            new_route_table.main_association_id = new_association_id\n        else:\n            association_target_id = previous_route_table.associations.pop(\n                association_id\n            )\n            new_route_table.associations[new_association_id] = association_target_id\n        return new_association_id\n\n\n# TODO: refractor to isloate class methods from backend logic\nclass Route(CloudFormationModel):\n    def __init__(\n        self,\n        route_table,\n        destination_cidr_block,\n        destination_ipv6_cidr_block,\n        destination_prefix_list=None,\n        local=False,\n        gateway=None,\n        instance=None,\n        nat_gateway=None,\n        egress_only_igw=None,\n        transit_gateway=None,\n        interface=None,\n        vpc_pcx=None,\n        carrier_gateway=None,\n    ):\n        self.id = generate_route_id(\n            route_table.id,\n            destination_cidr_block,\n            destination_ipv6_cidr_block,\n            destination_prefix_list.id if destination_prefix_list else None,\n        )\n        self.route_table = route_table\n        self.destination_cidr_block = destination_cidr_block\n        self.destination_ipv6_cidr_block = destination_ipv6_cidr_block\n        self.destination_prefix_list = destination_prefix_list\n        self.local = local\n        self.gateway = gateway\n        self.instance = instance\n        self.nat_gateway = nat_gateway\n        self.egress_only_igw = egress_only_igw\n        self.transit_gateway = transit_gateway\n        self.interface = interface\n        self.vpc_pcx = vpc_pcx\n        self.carrier_gateway = carrier_gateway\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    @staticmethod\n    def cloudformation_name_type():\n        return None\n\n    @staticmethod\n    def cloudformation_type():\n        # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route.html\n        return \"AWS::EC2::Route\"\n\n    @classmethod\n    def create_from_cloudformation_json(\n        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs\n    ):\n        from ..models import ec2_backends\n\n        properties = cloudformation_json[\"Properties\"]\n\n        gateway_id = properties.get(\"GatewayId\")\n        instance_id = properties.get(\"InstanceId\")\n        interface_id = properties.get(\"NetworkInterfaceId\")\n        nat_gateway_id = properties.get(\"NatGatewayId\")\n        egress_only_igw_id = properties.get(\"EgressOnlyInternetGatewayId\")\n        transit_gateway_id = properties.get(\"TransitGatewayId\")\n        pcx_id = properties.get(\"VpcPeeringConnectionId\")\n\n        route_table_id = properties[\"RouteTableId\"]\n        ec2_backend = ec2_backends[account_id][region_name]\n        route_table = ec2_backend.create_route(\n            route_table_id=route_table_id,\n            destination_cidr_block=properties.get(\"DestinationCidrBlock\"),\n            gateway_id=gateway_id,\n            instance_id=instance_id,\n            nat_gateway_id=nat_gateway_id,\n            egress_only_igw_id=egress_only_igw_id,\n            transit_gateway_id=transit_gateway_id,\n            interface_id=interface_id,\n            vpc_peering_connection_id=pcx_id,\n        )\n        return route_table\n\n\nclass RouteBackend:\n    def create_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n        local=False,\n        gateway_id=None,\n        instance_id=None,\n        nat_gateway_id=None,\n        egress_only_igw_id=None,\n        transit_gateway_id=None,\n        interface_id=None,\n        vpc_peering_connection_id=None,\n        carrier_gateway_id=None,\n    ):\n        gateway = None\n        nat_gateway = None\n        transit_gateway = None\n        egress_only_igw = None\n        interface = None\n        destination_prefix_list = None\n        carrier_gateway = None\n\n        route_table = self.get_route_table(route_table_id)\n\n        if interface_id:\n            # for validating interface Id whether it is valid or not.\n            interface = self.get_network_interface(interface_id)\n\n        else:\n            if gateway_id:\n                if EC2_RESOURCE_TO_PREFIX[\"vpn-gateway\"] in gateway_id:\n                    gateway = self.get_vpn_gateway(gateway_id)\n                elif EC2_RESOURCE_TO_PREFIX[\"internet-gateway\"] in gateway_id:\n                    gateway = self.get_internet_gateway(gateway_id)\n                elif EC2_RESOURCE_TO_PREFIX[\"vpc-endpoint\"] in gateway_id:\n                    gateway = self.get_vpc_end_point(gateway_id)\n\n            if destination_cidr_block:\n                self.__validate_destination_cidr_block(\n                    destination_cidr_block, route_table\n                )\n\n            if nat_gateway_id is not None:\n                nat_gateway = self.nat_gateways.get(nat_gateway_id)\n            if egress_only_igw_id is not None:\n                egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)\n            if transit_gateway_id is not None:\n                transit_gateway = self.transit_gateways.get(transit_gateway_id)\n            if destination_prefix_list_id is not None:\n                destination_prefix_list = self.managed_prefix_lists.get(\n                    destination_prefix_list_id\n                )\n            if carrier_gateway_id is not None:\n                carrier_gateway = self.carrier_gateways.get(carrier_gateway_id)\n\n        route = Route(\n            route_table,\n            destination_cidr_block,\n            destination_ipv6_cidr_block,\n            destination_prefix_list,\n            local=local,\n            gateway=gateway,\n            instance=self.get_instance(instance_id) if instance_id else None,\n            nat_gateway=nat_gateway,\n            egress_only_igw=egress_only_igw,\n            transit_gateway=transit_gateway,\n            interface=interface,\n            carrier_gateway=carrier_gateway,\n            vpc_pcx=self.get_vpc_peering_connection(vpc_peering_connection_id)\n            if vpc_peering_connection_id\n            else None,\n        )\n        route_table.routes[route.id] = route\n        return route\n\n    def replace_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n        nat_gateway_id=None,\n        egress_only_igw_id=None,\n        transit_gateway_id=None,\n        gateway_id=None,\n        instance_id=None,\n        interface_id=None,\n        vpc_peering_connection_id=None,\n    ):\n        route_table = self.get_route_table(route_table_id)\n        route_id = generate_route_id(\n            route_table.id, destination_cidr_block, destination_ipv6_cidr_block\n        )\n        route = route_table.routes[route_id]\n\n        if interface_id:\n            self.raise_not_implemented_error(\"ReplaceRoute to NetworkInterfaceId\")\n\n        route.gateway = None\n        route.nat_gateway = None\n        route.egress_only_igw = None\n        route.transit_gateway = None\n        if gateway_id:\n            if EC2_RESOURCE_TO_PREFIX[\"vpn-gateway\"] in gateway_id:\n                route.gateway = self.get_vpn_gateway(gateway_id)\n            elif EC2_RESOURCE_TO_PREFIX[\"internet-gateway\"] in gateway_id:\n                route.gateway = self.get_internet_gateway(gateway_id)\n\n        if nat_gateway_id is not None:\n            route.nat_gateway = self.nat_gateways.get(nat_gateway_id)\n        if egress_only_igw_id is not None:\n            route.egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)\n        if transit_gateway_id is not None:\n            route.transit_gateway = self.transit_gateways.get(transit_gateway_id)\n        if destination_prefix_list_id is not None:\n            route.prefix_list = self.managed_prefix_lists.get(\n                destination_prefix_list_id\n            )\n\n        route.instance = self.get_instance(instance_id) if instance_id else None\n        route.interface = None\n        route.vpc_pcx = (\n            self.get_vpc_peering_connection(vpc_peering_connection_id)\n            if vpc_peering_connection_id\n            else None\n        )\n\n        route_table.routes[route.id] = route\n        return route\n\n    def get_route(self, route_id):\n        route_table_id, _ = split_route_id(route_id)\n        route_table = self.get_route_table(route_table_id)\n        return route_table.get(route_id)\n\n    def delete_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n    ):\n        cidr = destination_cidr_block\n        route_table = self.get_route_table(route_table_id)\n        if destination_ipv6_cidr_block:\n            cidr = destination_ipv6_cidr_block\n        if destination_prefix_list_id:\n            cidr = destination_prefix_list_id\n        route_id = generate_route_id(route_table_id, cidr)\n        deleted = route_table.routes.pop(route_id, None)\n        if not deleted:\n            raise InvalidRouteError(route_table_id, cidr)\n        return deleted\n\n    def __validate_destination_cidr_block(self, destination_cidr_block, route_table):\n        \"\"\"\n        Utility function to check the destination CIDR block\n        Will validate the format and check for overlap with existing routes\n        \"\"\"\n        try:\n            ip_v4_network = ipaddress.IPv4Network(\n                str(destination_cidr_block), strict=False\n            )\n        except ValueError:\n            raise InvalidDestinationCIDRBlockParameterError(destination_cidr_block)\n\n        if not route_table.routes:\n            return\n        for route in route_table.routes.values():\n            if not route.destination_cidr_block:\n                continue\n            if not route.local and ip_v4_network.overlaps(\n                ipaddress.IPv4Network(str(route.destination_cidr_block))\n            ):\n                raise RouteAlreadyExistsError(destination_cidr_block)\n","header":{"file":{"path":"moto/ec2/models/route_tables.py"},"misc_line":null},"index_line":null,"is_binary_file":false,"binary_line":null,"minus_file":{"path":"a/moto/ec2/models/route_tables.py"},"plus_file":{"path":"b/moto/ec2/models/route_tables.py"},"hunks":[{"descriptor":{"old_range":{"start":86,"length":6},"new_range":{"start":86,"length":12},"section":"def get_filter_value(self, filter_name):"},"line_group":{"all_lines":[{"content":"                for route in self.routes.values()","type":"context"},{"content":"                if route.gateway is not None","type":"context"},{"content":"            ]","type":"context"},{"content":"        elif filter_name == \"route.vpc-peering-connection-id\":","type":"added"},{"content":"            return [","type":"added"},{"content":"                route.vpc_pcx.id","type":"added"},{"content":"                for route in self.routes.values()","type":"added"},{"content":"                if route.vpc_pcx is not None","type":"added"},{"content":"            ]","type":"added"},{"content":"        else:","type":"context"},{"content":"            return super().get_filter_value(filter_name, \"DescribeRouteTables\")","type":"context"},{"content":"","type":"context"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]}]}],"old_commit_hash":"c0b581aa08b234ed036c43901cee84cc9e955fa4","new_commit_hash":"0f160cc8444edb36dd4e1d91aa5ea18baf5fac3d","commit_message":"Implement filter `route.vpc-peering-connection-id` for DescribeRouteTables","commit_date":"2022-10-26T00:34:32-07:00","metadata":{}}
problem_statement: Implement filter 'route.vpc-peering-connection-id' for DescribeRouteTables
  Hi, when I try to mock the DescribeRouteTables I got the following error.
  
  `FilterNotImplementedError: The filter 'route.vpc-peering-connection-id' for DescribeRouteTables has not been implemented in Moto yet. Feel free to open an issue at https://github.com/spulec/moto/issues
  `
  
  It would be nice to add this filter to moto, thanks!
  
patch: diff --git a/moto/ec2/models/route_tables.py b/moto/ec2/models/route_tables.py
  --- a/moto/ec2/models/route_tables.py
  +++ b/moto/ec2/models/route_tables.py
  @@ -86,6 +86,12 @@ def get_filter_value(self, filter_name):
                   for route in self.routes.values()
                   if route.gateway is not None
               ]
  +        elif filter_name == "route.vpc-peering-connection-id":
  +            return [
  +                route.vpc_pcx.id
  +                for route in self.routes.values()
  +                if route.vpc_pcx is not None
  +            ]
           else:
               return super().get_filter_value(filter_name, "DescribeRouteTables")
   
   
  
file_context: {"moto/ec2/models/route_tables.py": "import ipaddress\n\nfrom moto.core import CloudFormationModel\nfrom .core import TaggedEC2Resource\nfrom ..exceptions import (\n    DependencyViolationError,\n    InvalidRouteError,\n    InvalidRouteTableIdError,\n    InvalidAssociationIdError,\n    InvalidDestinationCIDRBlockParameterError,\n    RouteAlreadyExistsError,\n)\nfrom ..utils import (\n    EC2_RESOURCE_TO_PREFIX,\n    generate_route_id,\n    generic_filter,\n    random_subnet_association_id,\n    random_route_table_id,\n    split_route_id,\n)\n\n\nclass RouteTable(TaggedEC2Resource, CloudFormationModel):\n    def __init__(self, ec2_backend, route_table_id, vpc_id, main=False):\n        self.ec2_backend = ec2_backend\n        self.id = route_table_id\n        self.vpc_id = vpc_id\n        if main:\n            self.main_association_id = random_subnet_association_id()\n        else:\n            self.main_association_id = None\n        self.associations = {}\n        self.routes = {}\n\n    @property\n    def owner_id(self):\n        return self.ec2_backend.account_id\n\n    @staticmethod\n    def cloudformation_name_type():\n        return None\n\n    @staticmethod\n    def cloudformation_type():\n        # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html\n        return \"AWS::EC2::RouteTable\"\n\n    @classmethod\n    def create_from_cloudformation_json(\n        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs\n    ):\n        from ..models import ec2_backends\n\n        properties = cloudformation_json[\"Properties\"]\n\n        vpc_id = properties[\"VpcId\"]\n        ec2_backend = ec2_backends[account_id][region_name]\n        route_table = ec2_backend.create_route_table(vpc_id=vpc_id)\n        return route_table\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    def get_filter_value(self, filter_name):\n        if filter_name == \"association.main\":\n            # Note: Boto only supports 'true'.\n            # https://github.com/boto/boto/issues/1742\n            if self.main_association_id is not None:\n                return \"true\"\n            else:\n                return \"false\"\n        elif filter_name == \"route-table-id\":\n            return self.id\n        elif filter_name == \"vpc-id\":\n            return self.vpc_id\n        elif filter_name == \"association.route-table-id\":\n            return self.id\n        elif filter_name == \"association.route-table-association-id\":\n            return self.all_associations_ids\n        elif filter_name == \"association.subnet-id\":\n            return self.associations.values()\n        elif filter_name == \"route.gateway-id\":\n            return [\n                route.gateway.id\n                for route in self.routes.values()\n                if route.gateway is not None\n            ]\n        else:\n            return super().get_filter_value(filter_name, \"DescribeRouteTables\")\n\n    @property\n    def all_associations_ids(self):\n        # NOTE(yoctozepto): Doing an explicit copy to not touch the original.\n        all_associations = set(self.associations)\n        if self.main_association_id is not None:\n            all_associations.add(self.main_association_id)\n        return all_associations\n\n\nclass RouteTableBackend:\n    def __init__(self):\n        self.route_tables = {}\n\n    def create_route_table(self, vpc_id, tags=None, main=False):\n        route_table_id = random_route_table_id()\n        vpc = self.get_vpc(vpc_id)  # Validate VPC exists\n        route_table = RouteTable(self, route_table_id, vpc_id, main=main)\n        for tag in tags or []:\n            route_table.add_tag(tag.get(\"Key\"), tag.get(\"Value\"))\n        self.route_tables[route_table_id] = route_table\n\n        # creating default routes for ipv4 cirds\n        ipv4_cidrs = vpc.get_cidr_block_association_set(ipv6=False)\n        for ipv4_cidr in ipv4_cidrs:\n            self.create_route(route_table_id, ipv4_cidr.get(\"cidr_block\"), local=True)\n\n        # creating default routes for ipv6 cidrs\n        ipv6_cidrs = vpc.get_cidr_block_association_set(ipv6=True)\n        for ipv6_cidr in ipv6_cidrs:\n            self.create_route(\n                route_table_id,\n                destination_cidr_block=None,\n                local=True,\n                destination_ipv6_cidr_block=ipv6_cidr.get(\"cidr_block\"),\n            )\n\n        return route_table\n\n    def get_route_table(self, route_table_id):\n        route_table = self.route_tables.get(route_table_id, None)\n        if not route_table:\n            raise InvalidRouteTableIdError(route_table_id)\n        return route_table\n\n    def describe_route_tables(self, route_table_ids=None, filters=None):\n        route_tables = self.route_tables.copy().values()\n\n        if route_table_ids:\n            route_tables = [\n                route_table\n                for route_table in route_tables\n                if route_table.id in route_table_ids\n            ]\n            if len(route_tables) != len(route_table_ids):\n                invalid_id = list(\n                    set(route_table_ids).difference(\n                        set([route_table.id for route_table in route_tables])\n                    )\n                )[0]\n                raise InvalidRouteTableIdError(invalid_id)\n\n        return generic_filter(filters, route_tables)\n\n    def delete_route_table(self, route_table_id):\n        route_table = self.get_route_table(route_table_id)\n        if route_table.associations:\n            raise DependencyViolationError(\n                \"The routeTable '{0}' has dependencies and cannot be deleted.\".format(\n                    route_table_id\n                )\n            )\n        self.route_tables.pop(route_table_id)\n        return True\n\n    def associate_route_table(self, route_table_id, gateway_id=None, subnet_id=None):\n        # Idempotent if association already exists.\n        route_tables_by_subnet = self.describe_route_tables(\n            filters={\"association.subnet-id\": [subnet_id]}\n        )\n        if route_tables_by_subnet:\n            for association_id, check_subnet_id in route_tables_by_subnet[\n                0\n            ].associations.items():\n                if subnet_id == check_subnet_id:\n                    return association_id\n\n        # Association does not yet exist, so create it.\n        route_table = self.get_route_table(route_table_id)\n        if gateway_id is None:\n            self.get_subnet(subnet_id)  # Validate subnet exists\n            association_id = random_subnet_association_id()\n            route_table.associations[association_id] = subnet_id\n            return association_id\n        if subnet_id is None:\n            association_id = random_subnet_association_id()\n            route_table.associations[association_id] = gateway_id\n            return association_id\n\n    def disassociate_route_table(self, association_id):\n        for route_table in self.route_tables.values():\n            if association_id in route_table.associations:\n                return route_table.associations.pop(association_id, None)\n        raise InvalidAssociationIdError(association_id)\n\n    def replace_route_table_association(self, association_id, route_table_id):\n        # Idempotent if association already exists.\n        new_route_table = self.get_route_table(route_table_id)\n        if association_id in new_route_table.all_associations_ids:\n            return association_id\n\n        # Find route table which currently has the association, error if none.\n        route_tables_by_association_id = self.describe_route_tables(\n            filters={\"association.route-table-association-id\": [association_id]}\n        )\n        if not route_tables_by_association_id:\n            raise InvalidAssociationIdError(association_id)\n        previous_route_table = route_tables_by_association_id[0]\n\n        # Remove existing association, create new one.\n        new_association_id = random_subnet_association_id()\n        if previous_route_table.main_association_id == association_id:\n            previous_route_table.main_association_id = None\n            new_route_table.main_association_id = new_association_id\n        else:\n            association_target_id = previous_route_table.associations.pop(\n                association_id\n            )\n            new_route_table.associations[new_association_id] = association_target_id\n        return new_association_id\n\n\n# TODO: refractor to isloate class methods from backend logic\nclass Route(CloudFormationModel):\n    def __init__(\n        self,\n        route_table,\n        destination_cidr_block,\n        destination_ipv6_cidr_block,\n        destination_prefix_list=None,\n        local=False,\n        gateway=None,\n        instance=None,\n        nat_gateway=None,\n        egress_only_igw=None,\n        transit_gateway=None,\n        interface=None,\n        vpc_pcx=None,\n        carrier_gateway=None,\n    ):\n        self.id = generate_route_id(\n            route_table.id,\n            destination_cidr_block,\n            destination_ipv6_cidr_block,\n            destination_prefix_list.id if destination_prefix_list else None,\n        )\n        self.route_table = route_table\n        self.destination_cidr_block = destination_cidr_block\n        self.destination_ipv6_cidr_block = destination_ipv6_cidr_block\n        self.destination_prefix_list = destination_prefix_list\n        self.local = local\n        self.gateway = gateway\n        self.instance = instance\n        self.nat_gateway = nat_gateway\n        self.egress_only_igw = egress_only_igw\n        self.transit_gateway = transit_gateway\n        self.interface = interface\n        self.vpc_pcx = vpc_pcx\n        self.carrier_gateway = carrier_gateway\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    @staticmethod\n    def cloudformation_name_type():\n        return None\n\n    @staticmethod\n    def cloudformation_type():\n        # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route.html\n        return \"AWS::EC2::Route\"\n\n    @classmethod\n    def create_from_cloudformation_json(\n        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs\n    ):\n        from ..models import ec2_backends\n\n        properties = cloudformation_json[\"Properties\"]\n\n        gateway_id = properties.get(\"GatewayId\")\n        instance_id = properties.get(\"InstanceId\")\n        interface_id = properties.get(\"NetworkInterfaceId\")\n        nat_gateway_id = properties.get(\"NatGatewayId\")\n        egress_only_igw_id = properties.get(\"EgressOnlyInternetGatewayId\")\n        transit_gateway_id = properties.get(\"TransitGatewayId\")\n        pcx_id = properties.get(\"VpcPeeringConnectionId\")\n\n        route_table_id = properties[\"RouteTableId\"]\n        ec2_backend = ec2_backends[account_id][region_name]\n        route_table = ec2_backend.create_route(\n            route_table_id=route_table_id,\n            destination_cidr_block=properties.get(\"DestinationCidrBlock\"),\n            gateway_id=gateway_id,\n            instance_id=instance_id,\n            nat_gateway_id=nat_gateway_id,\n            egress_only_igw_id=egress_only_igw_id,\n            transit_gateway_id=transit_gateway_id,\n            interface_id=interface_id,\n            vpc_peering_connection_id=pcx_id,\n        )\n        return route_table\n\n\nclass RouteBackend:\n    def create_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n        local=False,\n        gateway_id=None,\n        instance_id=None,\n        nat_gateway_id=None,\n        egress_only_igw_id=None,\n        transit_gateway_id=None,\n        interface_id=None,\n        vpc_peering_connection_id=None,\n        carrier_gateway_id=None,\n    ):\n        gateway = None\n        nat_gateway = None\n        transit_gateway = None\n        egress_only_igw = None\n        interface = None\n        destination_prefix_list = None\n        carrier_gateway = None\n\n        route_table = self.get_route_table(route_table_id)\n\n        if interface_id:\n            # for validating interface Id whether it is valid or not.\n            interface = self.get_network_interface(interface_id)\n\n        else:\n            if gateway_id:\n                if EC2_RESOURCE_TO_PREFIX[\"vpn-gateway\"] in gateway_id:\n                    gateway = self.get_vpn_gateway(gateway_id)\n                elif EC2_RESOURCE_TO_PREFIX[\"internet-gateway\"] in gateway_id:\n                    gateway = self.get_internet_gateway(gateway_id)\n                elif EC2_RESOURCE_TO_PREFIX[\"vpc-endpoint\"] in gateway_id:\n                    gateway = self.get_vpc_end_point(gateway_id)\n\n            if destination_cidr_block:\n                self.__validate_destination_cidr_block(\n                    destination_cidr_block, route_table\n                )\n\n            if nat_gateway_id is not None:\n                nat_gateway = self.nat_gateways.get(nat_gateway_id)\n            if egress_only_igw_id is not None:\n                egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)\n            if transit_gateway_id is not None:\n                transit_gateway = self.transit_gateways.get(transit_gateway_id)\n            if destination_prefix_list_id is not None:\n                destination_prefix_list = self.managed_prefix_lists.get(\n                    destination_prefix_list_id\n                )\n            if carrier_gateway_id is not None:\n                carrier_gateway = self.carrier_gateways.get(carrier_gateway_id)\n\n        route = Route(\n            route_table,\n            destination_cidr_block,\n            destination_ipv6_cidr_block,\n            destination_prefix_list,\n            local=local,\n            gateway=gateway,\n            instance=self.get_instance(instance_id) if instance_id else None,\n            nat_gateway=nat_gateway,\n            egress_only_igw=egress_only_igw,\n            transit_gateway=transit_gateway,\n            interface=interface,\n            carrier_gateway=carrier_gateway,\n            vpc_pcx=self.get_vpc_peering_connection(vpc_peering_connection_id)\n            if vpc_peering_connection_id\n            else None,\n        )\n        route_table.routes[route.id] = route\n        return route\n\n    def replace_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n        nat_gateway_id=None,\n        egress_only_igw_id=None,\n        transit_gateway_id=None,\n        gateway_id=None,\n        instance_id=None,\n        interface_id=None,\n        vpc_peering_connection_id=None,\n    ):\n        route_table = self.get_route_table(route_table_id)\n        route_id = generate_route_id(\n            route_table.id, destination_cidr_block, destination_ipv6_cidr_block\n        )\n        route = route_table.routes[route_id]\n\n        if interface_id:\n            self.raise_not_implemented_error(\"ReplaceRoute to NetworkInterfaceId\")\n\n        route.gateway = None\n        route.nat_gateway = None\n        route.egress_only_igw = None\n        route.transit_gateway = None\n        if gateway_id:\n            if EC2_RESOURCE_TO_PREFIX[\"vpn-gateway\"] in gateway_id:\n                route.gateway = self.get_vpn_gateway(gateway_id)\n            elif EC2_RESOURCE_TO_PREFIX[\"internet-gateway\"] in gateway_id:\n                route.gateway = self.get_internet_gateway(gateway_id)\n\n        if nat_gateway_id is not None:\n            route.nat_gateway = self.nat_gateways.get(nat_gateway_id)\n        if egress_only_igw_id is not None:\n            route.egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)\n        if transit_gateway_id is not None:\n            route.transit_gateway = self.transit_gateways.get(transit_gateway_id)\n        if destination_prefix_list_id is not None:\n            route.prefix_list = self.managed_prefix_lists.get(\n                destination_prefix_list_id\n            )\n\n        route.instance = self.get_instance(instance_id) if instance_id else None\n        route.interface = None\n        route.vpc_pcx = (\n            self.get_vpc_peering_connection(vpc_peering_connection_id)\n            if vpc_peering_connection_id\n            else None\n        )\n\n        route_table.routes[route.id] = route\n        return route\n\n    def get_route(self, route_id):\n        route_table_id, _ = split_route_id(route_id)\n        route_table = self.get_route_table(route_table_id)\n        return route_table.get(route_id)\n\n    def delete_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n    ):\n        cidr = destination_cidr_block\n        route_table = self.get_route_table(route_table_id)\n        if destination_ipv6_cidr_block:\n            cidr = destination_ipv6_cidr_block\n        if destination_prefix_list_id:\n            cidr = destination_prefix_list_id\n        route_id = generate_route_id(route_table_id, cidr)\n        deleted = route_table.routes.pop(route_id, None)\n        if not deleted:\n            raise InvalidRouteError(route_table_id, cidr)\n        return deleted\n\n    def __validate_destination_cidr_block(self, destination_cidr_block, route_table):\n        \"\"\"\n        Utility function to check the destination CIDR block\n        Will validate the format and check for overlap with existing routes\n        \"\"\"\n        try:\n            ip_v4_network = ipaddress.IPv4Network(\n                str(destination_cidr_block), strict=False\n            )\n        except ValueError:\n            raise InvalidDestinationCIDRBlockParameterError(destination_cidr_block)\n\n        if not route_table.routes:\n            return\n        for route in route_table.routes.values():\n            if not route.destination_cidr_block:\n                continue\n            if not route.local and ip_v4_network.overlaps(\n                ipaddress.IPv4Network(str(route.destination_cidr_block))\n            ):\n                raise RouteAlreadyExistsError(destination_cidr_block)\n"}
filelevel_patches: {"moto/ec2/models/route_tables.py": "@@ -86,6 +86,12 @@ def get_filter_value(self, filter_name):\n                 for route in self.routes.values()\n                 if route.gateway is not None\n             ]\n+        elif filter_name == \"route.vpc-peering-connection-id\":\n+            return [\n+                route.vpc_pcx.id\n+                for route in self.routes.values()\n+                if route.vpc_pcx is not None\n+            ]\n         else:\n             return super().get_filter_value(filter_name, \"DescribeRouteTables\")"}
messages.content: 
  We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Implement filter 'route.vpc-peering-connection-id' for DescribeRouteTables
  Hi, when I try to mock the DescribeRouteTables I got the following error.
  
  `FilterNotImplementedError: The filter 'route.vpc-peering-connection-id' for DescribeRouteTables has not been implemented in Moto yet. Feel free to open an issue at https://github.com/spulec/moto/issues
  `
  
  It would be nice to add this filter to moto, thanks!
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  
  --- BEGIN FILE ---
  ```
  ### moto/ec2/models/route_tables.py
  import ipaddress
  
  from moto.core import CloudFormationModel
  from .core import TaggedEC2Resource
  from ..exceptions import (
      DependencyViolationError,
      InvalidRouteError,
      InvalidRouteTableIdError,
      InvalidAssociationIdError,
      InvalidDestinationCIDRBlockParameterError,
      RouteAlreadyExistsError,
  )
  from ..utils import (
      EC2_RESOURCE_TO_PREFIX,
      generate_route_id,
      generic_filter,
      random_subnet_association_id,
      random_route_table_id,
      split_route_id,
  )
  
  
  class RouteTable(TaggedEC2Resource, CloudFormationModel):
      def __init__(self, ec2_backend, route_table_id, vpc_id, main=False):
          self.ec2_backend = ec2_backend
          self.id = route_table_id
          self.vpc_id = vpc_id
          if main:
              self.main_association_id = random_subnet_association_id()
          else:
              self.main_association_id = None
          self.associations = {}
          self.routes = {}
  
      @property
      def owner_id(self):
          return self.ec2_backend.account_id
  
      @staticmethod
      def cloudformation_name_type():
          return None
  
      @staticmethod
      def cloudformation_type():
          # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html
          return "AWS::EC2::RouteTable"
  
      @classmethod
      def create_from_cloudformation_json(
          cls, resource_name, cloudformation_json, account_id, region_name, **kwargs
      ):
          from ..models import ec2_backends
  
          properties = cloudformation_json["Properties"]
  
          vpc_id = properties["VpcId"]
          ec2_backend = ec2_backends[account_id][region_name]
          route_table = ec2_backend.create_route_table(vpc_id=vpc_id)
          return route_table
  
      @property
      def physical_resource_id(self):
          return self.id
  
      def get_filter_value(self, filter_name):
          if filter_name == "association.main":
              # Note: Boto only supports 'true'.
              # https://github.com/boto/boto/issues/1742
              if self.main_association_id is not None:
                  return "true"
              else:
                  return "false"
          elif filter_name == "route-table-id":
              return self.id
          elif filter_name == "vpc-id":
              return self.vpc_id
          elif filter_name == "association.route-table-id":
              return self.id
          elif filter_name == "association.route-table-association-id":
              return self.all_associations_ids
          elif filter_name == "association.subnet-id":
              return self.associations.values()
          elif filter_name == "route.gateway-id":
              return [
                  route.gateway.id
                  for route in self.routes.values()
                  if route.gateway is not None
              ]
          else:
              return super().get_filter_value(filter_name, "DescribeRouteTables")
  
      @property
      def all_associations_ids(self):
          # NOTE(yoctozepto): Doing an explicit copy to not touch the original.
          all_associations = set(self.associations)
          if self.main_association_id is not None:
              all_associations.add(self.main_association_id)
          return all_associations
  
  
  class RouteTableBackend:
      def __init__(self):
          self.route_tables = {}
  
      def create_route_table(self, vpc_id, tags=None, main=False):
          route_table_id = random_route_table_id()
          vpc = self.get_vpc(vpc_id)  # Validate VPC exists
          route_table = RouteTable(self, route_table_id, vpc_id, main=main)
          for tag in tags or []:
              route_table.add_tag(tag.get("Key"), tag.get("Value"))
          self.route_tables[route_table_id] = route_table
  
          # creating default routes for ipv4 cirds
          ipv4_cidrs = vpc.get_cidr_block_association_set(ipv6=False)
          for ipv4_cidr in ipv4_cidrs:
              self.create_route(route_table_id, ipv4_cidr.get("cidr_block"), local=True)
  
          # creating default routes for ipv6 cidrs
          ipv6_cidrs = vpc.get_cidr_block_association_set(ipv6=True)
          for ipv6_cidr in ipv6_cidrs:
              self.create_route(
                  route_table_id,
                  destination_cidr_block=None,
                  local=True,
                  destination_ipv6_cidr_block=ipv6_cidr.get("cidr_block"),
              )
  
          return route_table
  
      def get_route_table(self, route_table_id):
          route_table = self.route_tables.get(route_table_id, None)
          if not route_table:
              raise InvalidRouteTableIdError(route_table_id)
          return route_table
  
      def describe_route_tables(self, route_table_ids=None, filters=None):
          route_tables = self.route_tables.copy().values()
  
          if route_table_ids:
              route_tables = [
                  route_table
                  for route_table in route_tables
                  if route_table.id in route_table_ids
              ]
              if len(route_tables) != len(route_table_ids):
                  invalid_id = list(
                      set(route_table_ids).difference(
                          set([route_table.id for route_table in route_tables])
                      )
                  )[0]
                  raise InvalidRouteTableIdError(invalid_id)
  
          return generic_filter(filters, route_tables)
  
      def delete_route_table(self, route_table_id):
          route_table = self.get_route_table(route_table_id)
          if route_table.associations:
              raise DependencyViolationError(
                  "The routeTable '{0}' has dependencies and cannot be deleted.".format(
                      route_table_id
                  )
              )
          self.route_tables.pop(route_table_id)
          return True
  
      def associate_route_table(self, route_table_id, gateway_id=None, subnet_id=None):
          # Idempotent if association already exists.
          route_tables_by_subnet = self.describe_route_tables(
              filters={"association.subnet-id": [subnet_id]}
          )
          if route_tables_by_subnet:
              for association_id, check_subnet_id in route_tables_by_subnet[
                  0
              ].associations.items():
                  if subnet_id == check_subnet_id:
                      return association_id
  
          # Association does not yet exist, so create it.
          route_table = self.get_route_table(route_table_id)
          if gateway_id is None:
              self.get_subnet(subnet_id)  # Validate subnet exists
              association_id = random_subnet_association_id()
              route_table.associations[association_id] = subnet_id
              return association_id
          if subnet_id is None:
              association_id = random_subnet_association_id()
              route_table.associations[association_id] = gateway_id
              return association_id
  
      def disassociate_route_table(self, association_id):
          for route_table in self.route_tables.values():
              if association_id in route_table.associations:
                  return route_table.associations.pop(association_id, None)
          raise InvalidAssociationIdError(association_id)
  
      def replace_route_table_association(self, association_id, route_table_id):
          # Idempotent if association already exists.
          new_route_table = self.get_route_table(route_table_id)
          if association_id in new_route_table.all_associations_ids:
              return association_id
  
          # Find route table which currently has the association, error if none.
          route_tables_by_association_id = self.describe_route_tables(
              filters={"association.route-table-association-id": [association_id]}
          )
          if not route_tables_by_association_id:
              raise InvalidAssociationIdError(association_id)
          previous_route_table = route_tables_by_association_id[0]
  
          # Remove existing association, create new one.
          new_association_id = random_subnet_association_id()
          if previous_route_table.main_association_id == association_id:
              previous_route_table.main_association_id = None
              new_route_table.main_association_id = new_association_id
          else:
              association_target_id = previous_route_table.associations.pop(
                  association_id
              )
              new_route_table.associations[new_association_id] = association_target_id
          return new_association_id
  
  
  # TODO: refractor to isloate class methods from backend logic
  class Route(CloudFormationModel):
      def __init__(
          self,
          route_table,
          destination_cidr_block,
          destination_ipv6_cidr_block,
          destination_prefix_list=None,
          local=False,
          gateway=None,
          instance=None,
          nat_gateway=None,
          egress_only_igw=None,
          transit_gateway=None,
          interface=None,
          vpc_pcx=None,
          carrier_gateway=None,
      ):
          self.id = generate_route_id(
              route_table.id,
              destination_cidr_block,
              destination_ipv6_cidr_block,
              destination_prefix_list.id if destination_prefix_list else None,
          )
          self.route_table = route_table
          self.destination_cidr_block = destination_cidr_block
          self.destination_ipv6_cidr_block = destination_ipv6_cidr_block
          self.destination_prefix_list = destination_prefix_list
          self.local = local
          self.gateway = gateway
          self.instance = instance
          self.nat_gateway = nat_gateway
          self.egress_only_igw = egress_only_igw
          self.transit_gateway = transit_gateway
          self.interface = interface
          self.vpc_pcx = vpc_pcx
          self.carrier_gateway = carrier_gateway
  
      @property
      def physical_resource_id(self):
          return self.id
  
      @staticmethod
      def cloudformation_name_type():
          return None
  
      @staticmethod
      def cloudformation_type():
          # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route.html
          return "AWS::EC2::Route"
  
      @classmethod
      def create_from_cloudformation_json(
          cls, resource_name, cloudformation_json, account_id, region_name, **kwargs
      ):
          from ..models import ec2_backends
  
          properties = cloudformation_json["Properties"]
  
          gateway_id = properties.get("GatewayId")
          instance_id = properties.get("InstanceId")
          interface_id = properties.get("NetworkInterfaceId")
          nat_gateway_id = properties.get("NatGatewayId")
          egress_only_igw_id = properties.get("EgressOnlyInternetGatewayId")
          transit_gateway_id = properties.get("TransitGatewayId")
          pcx_id = properties.get("VpcPeeringConnectionId")
  
          route_table_id = properties["RouteTableId"]
          ec2_backend = ec2_backends[account_id][region_name]
          route_table = ec2_backend.create_route(
              route_table_id=route_table_id,
              destination_cidr_block=properties.get("DestinationCidrBlock"),
              gateway_id=gateway_id,
              instance_id=instance_id,
              nat_gateway_id=nat_gateway_id,
              egress_only_igw_id=egress_only_igw_id,
              transit_gateway_id=transit_gateway_id,
              interface_id=interface_id,
              vpc_peering_connection_id=pcx_id,
          )
          return route_table
  
  
  class RouteBackend:
      def create_route(
          self,
          route_table_id,
          destination_cidr_block,
          destination_ipv6_cidr_block=None,
          destination_prefix_list_id=None,
          local=False,
          gateway_id=None,
          instance_id=None,
          nat_gateway_id=None,
          egress_only_igw_id=None,
          transit_gateway_id=None,
          interface_id=None,
          vpc_peering_connection_id=None,
          carrier_gateway_id=None,
      ):
          gateway = None
          nat_gateway = None
          transit_gateway = None
          egress_only_igw = None
          interface = None
          destination_prefix_list = None
          carrier_gateway = None
  
          route_table = self.get_route_table(route_table_id)
  
          if interface_id:
              # for validating interface Id whether it is valid or not.
              interface = self.get_network_interface(interface_id)
  
          else:
              if gateway_id:
                  if EC2_RESOURCE_TO_PREFIX["vpn-gateway"] in gateway_id:
                      gateway = self.get_vpn_gateway(gateway_id)
                  elif EC2_RESOURCE_TO_PREFIX["internet-gateway"] in gateway_id:
                      gateway = self.get_internet_gateway(gateway_id)
                  elif EC2_RESOURCE_TO_PREFIX["vpc-endpoint"] in gateway_id:
                      gateway = self.get_vpc_end_point(gateway_id)
  
              if destination_cidr_block:
                  self.__validate_destination_cidr_block(
                      destination_cidr_block, route_table
                  )
  
              if nat_gateway_id is not None:
                  nat_gateway = self.nat_gateways.get(nat_gateway_id)
              if egress_only_igw_id is not None:
                  egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)
              if transit_gateway_id is not None:
                  transit_gateway = self.transit_gateways.get(transit_gateway_id)
              if destination_prefix_list_id is not None:
                  destination_prefix_list = self.managed_prefix_lists.get(
                      destination_prefix_list_id
                  )
              if carrier_gateway_id is not None:
                  carrier_gateway = self.carrier_gateways.get(carrier_gateway_id)
  
          route = Route(
              route_table,
              destination_cidr_block,
              destination_ipv6_cidr_block,
              destination_prefix_list,
              local=local,
              gateway=gateway,
              instance=self.get_instance(instance_id) if instance_id else None,
              nat_gateway=nat_gateway,
              egress_only_igw=egress_only_igw,
              transit_gateway=transit_gateway,
              interface=interface,
              carrier_gateway=carrier_gateway,
              vpc_pcx=self.get_vpc_peering_connection(vpc_peering_connection_id)
              if vpc_peering_connection_id
              else None,
          )
          route_table.routes[route.id] = route
          return route
  
      def replace_route(
          self,
          route_table_id,
          destination_cidr_block,
          destination_ipv6_cidr_block=None,
          destination_prefix_list_id=None,
          nat_gateway_id=None,
          egress_only_igw_id=None,
          transit_gateway_id=None,
          gateway_id=None,
          instance_id=None,
          interface_id=None,
          vpc_peering_connection_id=None,
      ):
          route_table = self.get_route_table(route_table_id)
          route_id = generate_route_id(
              route_table.id, destination_cidr_block, destination_ipv6_cidr_block
          )
          route = route_table.routes[route_id]
  
          if interface_id:
              self.raise_not_implemented_error("ReplaceRoute to NetworkInterfaceId")
  
          route.gateway = None
          route.nat_gateway = None
          route.egress_only_igw = None
          route.transit_gateway = None
          if gateway_id:
              if EC2_RESOURCE_TO_PREFIX["vpn-gateway"] in gateway_id:
                  route.gateway = self.get_vpn_gateway(gateway_id)
              elif EC2_RESOURCE_TO_PREFIX["internet-gateway"] in gateway_id:
                  route.gateway = self.get_internet_gateway(gateway_id)
  
          if nat_gateway_id is not None:
              route.nat_gateway = self.nat_gateways.get(nat_gateway_id)
          if egress_only_igw_id is not None:
              route.egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)
          if transit_gateway_id is not None:
              route.transit_gateway = self.transit_gateways.get(transit_gateway_id)
          if destination_prefix_list_id is not None:
              route.prefix_list = self.managed_prefix_lists.get(
                  destination_prefix_list_id
              )
  
          route.instance = self.get_instance(instance_id) if instance_id else None
          route.interface = None
          route.vpc_pcx = (
              self.get_vpc_peering_connection(vpc_peering_connection_id)
              if vpc_peering_connection_id
              else None
          )
  
          route_table.routes[route.id] = route
          return route
  
      def get_route(self, route_id):
          route_table_id, _ = split_route_id(route_id)
          route_table = self.get_route_table(route_table_id)
          return route_table.get(route_id)
  
      def delete_route(
          self,
          route_table_id,
          destination_cidr_block,
          destination_ipv6_cidr_block=None,
          destination_prefix_list_id=None,
      ):
          cidr = destination_cidr_block
          route_table = self.get_route_table(route_table_id)
          if destination_ipv6_cidr_block:
              cidr = destination_ipv6_cidr_block
          if destination_prefix_list_id:
              cidr = destination_prefix_list_id
          route_id = generate_route_id(route_table_id, cidr)
          deleted = route_table.routes.pop(route_id, None)
          if not deleted:
              raise InvalidRouteError(route_table_id, cidr)
          return deleted
  
      def __validate_destination_cidr_block(self, destination_cidr_block, route_table):
          """
          Utility function to check the destination CIDR block
          Will validate the format and check for overlap with existing routes
          """
          try:
              ip_v4_network = ipaddress.IPv4Network(
                  str(destination_cidr_block), strict=False
              )
          except ValueError:
              raise InvalidDestinationCIDRBlockParameterError(destination_cidr_block)
  
          if not route_table.routes:
              return
          for route in route_table.routes.values():
              if not route.destination_cidr_block:
                  continue
              if not route.local and ip_v4_network.overlaps(
                  ipaddress.IPv4Network(str(route.destination_cidr_block))
              ):
                  raise RouteAlreadyExistsError(destination_cidr_block)
  
  ```
  --- END FILE ---
  
  Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.
  
  Every *SEARCH/REPLACE* edit must use this format:
  1. The file path
  2. The start of search block: <<<<<<< SEARCH
  3. A contiguous chunk of lines to search for in the existing source code
  4. The dividing line: =======
  5. The lines to replace into the source code
  6. The end of the replace block: >>>>>>> REPLACE
  
  Here is an example:
  
  ```python
  ### mathweb/flask/app.py
  <<<<<<< SEARCH
  from flask import Flask
  =======
  import math
  from flask import Flask
  >>>>>>> REPLACE
  ```
  
  Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
  Wrap the *SEARCH/REPLACE* edit in blocks ```python...```.
  
messages.role: user
verification_info: {"file_context": {"moto/ec2/models/route_tables.py": "import ipaddress\n\nfrom moto.core import CloudFormationModel\nfrom .core import TaggedEC2Resource\nfrom ..exceptions import (\n    DependencyViolationError,\n    InvalidRouteError,\n    InvalidRouteTableIdError,\n    InvalidAssociationIdError,\n    InvalidDestinationCIDRBlockParameterError,\n    RouteAlreadyExistsError,\n)\nfrom ..utils import (\n    EC2_RESOURCE_TO_PREFIX,\n    generate_route_id,\n    generic_filter,\n    random_subnet_association_id,\n    random_route_table_id,\n    split_route_id,\n)\n\n\nclass RouteTable(TaggedEC2Resource, CloudFormationModel):\n    def __init__(self, ec2_backend, route_table_id, vpc_id, main=False):\n        self.ec2_backend = ec2_backend\n        self.id = route_table_id\n        self.vpc_id = vpc_id\n        if main:\n            self.main_association_id = random_subnet_association_id()\n        else:\n            self.main_association_id = None\n        self.associations = {}\n        self.routes = {}\n\n    @property\n    def owner_id(self):\n        return self.ec2_backend.account_id\n\n    @staticmethod\n    def cloudformation_name_type():\n        return None\n\n    @staticmethod\n    def cloudformation_type():\n        # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html\n        return \"AWS::EC2::RouteTable\"\n\n    @classmethod\n    def create_from_cloudformation_json(\n        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs\n    ):\n        from ..models import ec2_backends\n\n        properties = cloudformation_json[\"Properties\"]\n\n        vpc_id = properties[\"VpcId\"]\n        ec2_backend = ec2_backends[account_id][region_name]\n        route_table = ec2_backend.create_route_table(vpc_id=vpc_id)\n        return route_table\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    def get_filter_value(self, filter_name):\n        if filter_name == \"association.main\":\n            # Note: Boto only supports 'true'.\n            # https://github.com/boto/boto/issues/1742\n            if self.main_association_id is not None:\n                return \"true\"\n            else:\n                return \"false\"\n        elif filter_name == \"route-table-id\":\n            return self.id\n        elif filter_name == \"vpc-id\":\n            return self.vpc_id\n        elif filter_name == \"association.route-table-id\":\n            return self.id\n        elif filter_name == \"association.route-table-association-id\":\n            return self.all_associations_ids\n        elif filter_name == \"association.subnet-id\":\n            return self.associations.values()\n        elif filter_name == \"route.gateway-id\":\n            return [\n                route.gateway.id\n                for route in self.routes.values()\n                if route.gateway is not None\n            ]\n        else:\n            return super().get_filter_value(filter_name, \"DescribeRouteTables\")\n\n    @property\n    def all_associations_ids(self):\n        # NOTE(yoctozepto): Doing an explicit copy to not touch the original.\n        all_associations = set(self.associations)\n        if self.main_association_id is not None:\n            all_associations.add(self.main_association_id)\n        return all_associations\n\n\nclass RouteTableBackend:\n    def __init__(self):\n        self.route_tables = {}\n\n    def create_route_table(self, vpc_id, tags=None, main=False):\n        route_table_id = random_route_table_id()\n        vpc = self.get_vpc(vpc_id)  # Validate VPC exists\n        route_table = RouteTable(self, route_table_id, vpc_id, main=main)\n        for tag in tags or []:\n            route_table.add_tag(tag.get(\"Key\"), tag.get(\"Value\"))\n        self.route_tables[route_table_id] = route_table\n\n        # creating default routes for ipv4 cirds\n        ipv4_cidrs = vpc.get_cidr_block_association_set(ipv6=False)\n        for ipv4_cidr in ipv4_cidrs:\n            self.create_route(route_table_id, ipv4_cidr.get(\"cidr_block\"), local=True)\n\n        # creating default routes for ipv6 cidrs\n        ipv6_cidrs = vpc.get_cidr_block_association_set(ipv6=True)\n        for ipv6_cidr in ipv6_cidrs:\n            self.create_route(\n                route_table_id,\n                destination_cidr_block=None,\n                local=True,\n                destination_ipv6_cidr_block=ipv6_cidr.get(\"cidr_block\"),\n            )\n\n        return route_table\n\n    def get_route_table(self, route_table_id):\n        route_table = self.route_tables.get(route_table_id, None)\n        if not route_table:\n            raise InvalidRouteTableIdError(route_table_id)\n        return route_table\n\n    def describe_route_tables(self, route_table_ids=None, filters=None):\n        route_tables = self.route_tables.copy().values()\n\n        if route_table_ids:\n            route_tables = [\n                route_table\n                for route_table in route_tables\n                if route_table.id in route_table_ids\n            ]\n            if len(route_tables) != len(route_table_ids):\n                invalid_id = list(\n                    set(route_table_ids).difference(\n                        set([route_table.id for route_table in route_tables])\n                    )\n                )[0]\n                raise InvalidRouteTableIdError(invalid_id)\n\n        return generic_filter(filters, route_tables)\n\n    def delete_route_table(self, route_table_id):\n        route_table = self.get_route_table(route_table_id)\n        if route_table.associations:\n            raise DependencyViolationError(\n                \"The routeTable '{0}' has dependencies and cannot be deleted.\".format(\n                    route_table_id\n                )\n            )\n        self.route_tables.pop(route_table_id)\n        return True\n\n    def associate_route_table(self, route_table_id, gateway_id=None, subnet_id=None):\n        # Idempotent if association already exists.\n        route_tables_by_subnet = self.describe_route_tables(\n            filters={\"association.subnet-id\": [subnet_id]}\n        )\n        if route_tables_by_subnet:\n            for association_id, check_subnet_id in route_tables_by_subnet[\n                0\n            ].associations.items():\n                if subnet_id == check_subnet_id:\n                    return association_id\n\n        # Association does not yet exist, so create it.\n        route_table = self.get_route_table(route_table_id)\n        if gateway_id is None:\n            self.get_subnet(subnet_id)  # Validate subnet exists\n            association_id = random_subnet_association_id()\n            route_table.associations[association_id] = subnet_id\n            return association_id\n        if subnet_id is None:\n            association_id = random_subnet_association_id()\n            route_table.associations[association_id] = gateway_id\n            return association_id\n\n    def disassociate_route_table(self, association_id):\n        for route_table in self.route_tables.values():\n            if association_id in route_table.associations:\n                return route_table.associations.pop(association_id, None)\n        raise InvalidAssociationIdError(association_id)\n\n    def replace_route_table_association(self, association_id, route_table_id):\n        # Idempotent if association already exists.\n        new_route_table = self.get_route_table(route_table_id)\n        if association_id in new_route_table.all_associations_ids:\n            return association_id\n\n        # Find route table which currently has the association, error if none.\n        route_tables_by_association_id = self.describe_route_tables(\n            filters={\"association.route-table-association-id\": [association_id]}\n        )\n        if not route_tables_by_association_id:\n            raise InvalidAssociationIdError(association_id)\n        previous_route_table = route_tables_by_association_id[0]\n\n        # Remove existing association, create new one.\n        new_association_id = random_subnet_association_id()\n        if previous_route_table.main_association_id == association_id:\n            previous_route_table.main_association_id = None\n            new_route_table.main_association_id = new_association_id\n        else:\n            association_target_id = previous_route_table.associations.pop(\n                association_id\n            )\n            new_route_table.associations[new_association_id] = association_target_id\n        return new_association_id\n\n\n# TODO: refractor to isloate class methods from backend logic\nclass Route(CloudFormationModel):\n    def __init__(\n        self,\n        route_table,\n        destination_cidr_block,\n        destination_ipv6_cidr_block,\n        destination_prefix_list=None,\n        local=False,\n        gateway=None,\n        instance=None,\n        nat_gateway=None,\n        egress_only_igw=None,\n        transit_gateway=None,\n        interface=None,\n        vpc_pcx=None,\n        carrier_gateway=None,\n    ):\n        self.id = generate_route_id(\n            route_table.id,\n            destination_cidr_block,\n            destination_ipv6_cidr_block,\n            destination_prefix_list.id if destination_prefix_list else None,\n        )\n        self.route_table = route_table\n        self.destination_cidr_block = destination_cidr_block\n        self.destination_ipv6_cidr_block = destination_ipv6_cidr_block\n        self.destination_prefix_list = destination_prefix_list\n        self.local = local\n        self.gateway = gateway\n        self.instance = instance\n        self.nat_gateway = nat_gateway\n        self.egress_only_igw = egress_only_igw\n        self.transit_gateway = transit_gateway\n        self.interface = interface\n        self.vpc_pcx = vpc_pcx\n        self.carrier_gateway = carrier_gateway\n\n    @property\n    def physical_resource_id(self):\n        return self.id\n\n    @staticmethod\n    def cloudformation_name_type():\n        return None\n\n    @staticmethod\n    def cloudformation_type():\n        # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route.html\n        return \"AWS::EC2::Route\"\n\n    @classmethod\n    def create_from_cloudformation_json(\n        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs\n    ):\n        from ..models import ec2_backends\n\n        properties = cloudformation_json[\"Properties\"]\n\n        gateway_id = properties.get(\"GatewayId\")\n        instance_id = properties.get(\"InstanceId\")\n        interface_id = properties.get(\"NetworkInterfaceId\")\n        nat_gateway_id = properties.get(\"NatGatewayId\")\n        egress_only_igw_id = properties.get(\"EgressOnlyInternetGatewayId\")\n        transit_gateway_id = properties.get(\"TransitGatewayId\")\n        pcx_id = properties.get(\"VpcPeeringConnectionId\")\n\n        route_table_id = properties[\"RouteTableId\"]\n        ec2_backend = ec2_backends[account_id][region_name]\n        route_table = ec2_backend.create_route(\n            route_table_id=route_table_id,\n            destination_cidr_block=properties.get(\"DestinationCidrBlock\"),\n            gateway_id=gateway_id,\n            instance_id=instance_id,\n            nat_gateway_id=nat_gateway_id,\n            egress_only_igw_id=egress_only_igw_id,\n            transit_gateway_id=transit_gateway_id,\n            interface_id=interface_id,\n            vpc_peering_connection_id=pcx_id,\n        )\n        return route_table\n\n\nclass RouteBackend:\n    def create_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n        local=False,\n        gateway_id=None,\n        instance_id=None,\n        nat_gateway_id=None,\n        egress_only_igw_id=None,\n        transit_gateway_id=None,\n        interface_id=None,\n        vpc_peering_connection_id=None,\n        carrier_gateway_id=None,\n    ):\n        gateway = None\n        nat_gateway = None\n        transit_gateway = None\n        egress_only_igw = None\n        interface = None\n        destination_prefix_list = None\n        carrier_gateway = None\n\n        route_table = self.get_route_table(route_table_id)\n\n        if interface_id:\n            # for validating interface Id whether it is valid or not.\n            interface = self.get_network_interface(interface_id)\n\n        else:\n            if gateway_id:\n                if EC2_RESOURCE_TO_PREFIX[\"vpn-gateway\"] in gateway_id:\n                    gateway = self.get_vpn_gateway(gateway_id)\n                elif EC2_RESOURCE_TO_PREFIX[\"internet-gateway\"] in gateway_id:\n                    gateway = self.get_internet_gateway(gateway_id)\n                elif EC2_RESOURCE_TO_PREFIX[\"vpc-endpoint\"] in gateway_id:\n                    gateway = self.get_vpc_end_point(gateway_id)\n\n            if destination_cidr_block:\n                self.__validate_destination_cidr_block(\n                    destination_cidr_block, route_table\n                )\n\n            if nat_gateway_id is not None:\n                nat_gateway = self.nat_gateways.get(nat_gateway_id)\n            if egress_only_igw_id is not None:\n                egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)\n            if transit_gateway_id is not None:\n                transit_gateway = self.transit_gateways.get(transit_gateway_id)\n            if destination_prefix_list_id is not None:\n                destination_prefix_list = self.managed_prefix_lists.get(\n                    destination_prefix_list_id\n                )\n            if carrier_gateway_id is not None:\n                carrier_gateway = self.carrier_gateways.get(carrier_gateway_id)\n\n        route = Route(\n            route_table,\n            destination_cidr_block,\n            destination_ipv6_cidr_block,\n            destination_prefix_list,\n            local=local,\n            gateway=gateway,\n            instance=self.get_instance(instance_id) if instance_id else None,\n            nat_gateway=nat_gateway,\n            egress_only_igw=egress_only_igw,\n            transit_gateway=transit_gateway,\n            interface=interface,\n            carrier_gateway=carrier_gateway,\n            vpc_pcx=self.get_vpc_peering_connection(vpc_peering_connection_id)\n            if vpc_peering_connection_id\n            else None,\n        )\n        route_table.routes[route.id] = route\n        return route\n\n    def replace_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n        nat_gateway_id=None,\n        egress_only_igw_id=None,\n        transit_gateway_id=None,\n        gateway_id=None,\n        instance_id=None,\n        interface_id=None,\n        vpc_peering_connection_id=None,\n    ):\n        route_table = self.get_route_table(route_table_id)\n        route_id = generate_route_id(\n            route_table.id, destination_cidr_block, destination_ipv6_cidr_block\n        )\n        route = route_table.routes[route_id]\n\n        if interface_id:\n            self.raise_not_implemented_error(\"ReplaceRoute to NetworkInterfaceId\")\n\n        route.gateway = None\n        route.nat_gateway = None\n        route.egress_only_igw = None\n        route.transit_gateway = None\n        if gateway_id:\n            if EC2_RESOURCE_TO_PREFIX[\"vpn-gateway\"] in gateway_id:\n                route.gateway = self.get_vpn_gateway(gateway_id)\n            elif EC2_RESOURCE_TO_PREFIX[\"internet-gateway\"] in gateway_id:\n                route.gateway = self.get_internet_gateway(gateway_id)\n\n        if nat_gateway_id is not None:\n            route.nat_gateway = self.nat_gateways.get(nat_gateway_id)\n        if egress_only_igw_id is not None:\n            route.egress_only_igw = self.get_egress_only_igw(egress_only_igw_id)\n        if transit_gateway_id is not None:\n            route.transit_gateway = self.transit_gateways.get(transit_gateway_id)\n        if destination_prefix_list_id is not None:\n            route.prefix_list = self.managed_prefix_lists.get(\n                destination_prefix_list_id\n            )\n\n        route.instance = self.get_instance(instance_id) if instance_id else None\n        route.interface = None\n        route.vpc_pcx = (\n            self.get_vpc_peering_connection(vpc_peering_connection_id)\n            if vpc_peering_connection_id\n            else None\n        )\n\n        route_table.routes[route.id] = route\n        return route\n\n    def get_route(self, route_id):\n        route_table_id, _ = split_route_id(route_id)\n        route_table = self.get_route_table(route_table_id)\n        return route_table.get(route_id)\n\n    def delete_route(\n        self,\n        route_table_id,\n        destination_cidr_block,\n        destination_ipv6_cidr_block=None,\n        destination_prefix_list_id=None,\n    ):\n        cidr = destination_cidr_block\n        route_table = self.get_route_table(route_table_id)\n        if destination_ipv6_cidr_block:\n            cidr = destination_ipv6_cidr_block\n        if destination_prefix_list_id:\n            cidr = destination_prefix_list_id\n        route_id = generate_route_id(route_table_id, cidr)\n        deleted = route_table.routes.pop(route_id, None)\n        if not deleted:\n            raise InvalidRouteError(route_table_id, cidr)\n        return deleted\n\n    def __validate_destination_cidr_block(self, destination_cidr_block, route_table):\n        \"\"\"\n        Utility function to check the destination CIDR block\n        Will validate the format and check for overlap with existing routes\n        \"\"\"\n        try:\n            ip_v4_network = ipaddress.IPv4Network(\n                str(destination_cidr_block), strict=False\n            )\n        except ValueError:\n            raise InvalidDestinationCIDRBlockParameterError(destination_cidr_block)\n\n        if not route_table.routes:\n            return\n        for route in route_table.routes.values():\n            if not route.destination_cidr_block:\n                continue\n            if not route.local and ip_v4_network.overlaps(\n                ipaddress.IPv4Network(str(route.destination_cidr_block))\n            ):\n                raise RouteAlreadyExistsError(destination_cidr_block)\n"}, "filelevel_patches": {"moto/ec2/models/route_tables.py": "@@ -86,6 +86,12 @@ def get_filter_value(self, filter_name):\n                 for route in self.routes.values()\n                 if route.gateway is not None\n             ]\n+        elif filter_name == \"route.vpc-peering-connection-id\":\n+            return [\n+                route.vpc_pcx.id\n+                for route in self.routes.values()\n+                if route.vpc_pcx is not None\n+            ]\n         else:\n             return super().get_filter_value(filter_name, \"DescribeRouteTables\")"}}