def test_init(self): model = FullModel() new0 = URLField() new1 = URLField() assert 1 == len(new0.default_validators) assert 1 == len(new1.default_validators) new0 = ASNField() new1 = ASNField() assert 0 == len(new0.default_validators) assert 0 == len(new1.default_validators) new0 = IPAddressField() new1 = IPAddressField() assert_ip_validator(new0) assert_ip_validator(new1) new0 = IPPrefixField() new1 = IPPrefixField() assert_ip_validator(new0) assert_ip_validator(new1) new0 = MacAddressField() new1 = MacAddressField() assert 1 == len(new0.default_validators) assert 1 == len(new1.default_validators)
class IXLanBase(HandleRefModel): name = models.CharField(_("Name"), max_length=255, blank=True) descr = models.TextField(_("Description"), blank=True) mtu = models.PositiveIntegerField("MTU", null=True, blank=True) vlan = models.PositiveIntegerField("VLAN", null=True, blank=True) dot1q_support = models.BooleanField("802.1Q", default=False) rs_asn = ASNField(verbose_name=_("Route Server ASN"), null=True, blank=True, default=0) arp_sponge = MacAddressField(verbose_name=_("ARP sponging MAC"), null=True, unique=True, blank=True) ixf_ixp_member_list_url = models.URLField( verbose_name=_("IX-F Member Export URL"), null=True, blank=True) ixf_ixp_member_list_url_visible = models.CharField( verbose_name=_("IX-F Member Export URL Visibility"), max_length=64, choices=const.VISIBILITY, default="Private", ) class Meta: abstract = True db_table = "%sixlan" % settings.TABLE_PREFIX verbose_name = _("Internet Exchange LAN") verbose_name_plural = _("Internet Exchange LANs") class HandleRef: tag = "ixlan" delete_cascade = ["ixpfx_set", "netixlan_set"]
class NetworkBase(HandleRefModel): asn = ASNField(unique=True) name = models.CharField(max_length=255, unique=True) aka = models.CharField(max_length=255, blank=True) irr_as_set = models.CharField(max_length=255, blank=True) website = URLField(blank=True) looking_glass = URLField(blank=True) route_server = URLField(blank=True) notes = models.TextField(blank=True) notes_private = models.TextField(blank=True) info_traffic = models.CharField(max_length=39, blank=True, choices=const.TRAFFIC) info_ratio = models.CharField(max_length=45, blank=True, choices=const.RATIOS, default='Not Disclosed') info_scope = models.CharField(max_length=39, blank=True, choices=const.SCOPES, default='Not Disclosed') info_type = models.CharField(max_length=60, blank=True, choices=const.NET_TYPES, default='Not Disclosed') info_prefixes4 = models.PositiveIntegerField(null=True, blank=True) info_prefixes6 = models.PositiveIntegerField(null=True, blank=True) info_unicast = models.BooleanField(default=False) info_multicast = models.BooleanField(default=False) info_ipv6 = models.BooleanField(default=False) policy_url = URLField(blank=True) policy_general = models.CharField(max_length=72, blank=True, choices=const.POLICY_GENERAL) policy_locations = models.CharField(max_length=72, blank=True, choices=const.POLICY_LOCATIONS) policy_ratio = models.BooleanField(default=False) policy_contracts = models.CharField(max_length=36, blank=True, choices=const.POLICY_CONTRACTS) class Meta: abstract = True db_table = '%snetwork' % settings.TABLE_PREFIX verbose_name_plural = "Networks" class HandleRef: tag = 'net' delete_cascade = ["poc_set", "netfac_set", "netixlan_set"] def __str__(self): return self.name
class NetworkFacilityBase(HandleRefModel): local_asn = ASNField(null=True, blank=True) avail_sonet = models.BooleanField(default=False) avail_ethernet = models.BooleanField(default=False) avail_atm = models.BooleanField(default=False) class Meta: abstract = True db_table = '%snetwork_facility' % settings.TABLE_PREFIX verbose_name_plural = "Network Facilities" class HandleRef: tag = 'netfac'
class NetworkFacilityBase(HandleRefModel): local_asn = ASNField(verbose_name=_("Local ASN"), null=True, blank=True) avail_sonet = models.BooleanField("SONET", default=False) avail_ethernet = models.BooleanField("Ethernet", default=False) avail_atm = models.BooleanField("ATM", default=False) class Meta: abstract = True db_table = "%snetwork_facility" % settings.TABLE_PREFIX verbose_name = _("Network Facility") verbose_name_plural = _("Network Facilities") class HandleRef: tag = "netfac"
class NetworkIXLanBase(HandleRefModel): asn = ASNField() ipaddr4 = IPAddressField(version=4, blank=True, null=True) ipaddr6 = IPAddressField(version=6, blank=True, null=True) is_rs_peer = models.BooleanField(default=False) notes = models.CharField(max_length=255, blank=True) speed = models.PositiveIntegerField() class Meta: abstract = True db_table = '%snetwork_ixlan' % settings.TABLE_PREFIX class HandleRef: tag = "netixlan"
class FullModel(models.Model): url = URLField(null=True, blank=True) asn = ASNField(null=True, blank=True) ipv4 = IPAddressField(version=4, null=True, blank=True) ipv6 = IPAddressField(version=6, null=True, blank=True) ip_address = IPAddressField(null=True, blank=True) prefix = IPPrefixField(null=True, blank=True) prefix4 = IPPrefixField(version=4, null=True, blank=True) prefix6 = IPPrefixField(version=6, null=True, blank=True) mac = MacAddressField(null=True, blank=True) class Meta: app_label = 'django_inet.tests'
class IXLanBase(HandleRefModel): name = models.CharField(max_length=255, blank=True) descr = models.TextField(blank=True) mtu = models.PositiveIntegerField(null=True, blank=True) vlan = models.PositiveIntegerField(null=True, blank=True) dot1q_support = models.BooleanField(default=False) rs_asn = ASNField(null=True, blank=True, default=0) arp_sponge = MacAddressField(null=True, unique=True, blank=True) class Meta: abstract = True db_table = '%sixlan' % settings.TABLE_PREFIX class HandleRef: tag = 'ixlan' delete_cascade = ["ixpfx_set", "netixlan_set"]
class NetworkIXLanBase(HandleRefModel): asn = ASNField(verbose_name="ASN") ipaddr4 = IPAddressField(verbose_name="IPv4", version=4, blank=True, null=True) ipaddr6 = IPAddressField(verbose_name="IPv6", version=6, blank=True, null=True) is_rs_peer = models.BooleanField(_("RS peer"), default=False) notes = models.CharField(_("Notes"), max_length=255, blank=True) speed = models.PositiveIntegerField(_("Speed (mbit/sec)")) operational = models.BooleanField(_("Operational"), default=True) class Meta: abstract = True db_table = "%snetwork_ixlan" % settings.TABLE_PREFIX verbose_name = _("Public Peering Exchange Point") verbose_name_plural = _("Public Peering Exchange Points") class HandleRef: tag = "netixlan"
class NetworkBase(HandleRefModel): asn = ASNField(verbose_name="ASN", unique=True) name = models.CharField(_("Name"), max_length=255, unique=True) aka = models.CharField(_("Also Known As"), max_length=255, blank=True) name_long = models.CharField(_("Long Name"), max_length=255, blank=True) irr_as_set = models.CharField( _("IRR as-set/route-set"), max_length=255, blank=True, help_text=_("Reference to an AS-SET or " "ROUTE-SET in Internet " "Routing Registry (IRR)"), ) website = URLField(_("Website"), blank=True) looking_glass = LG_URLField(_("Looking Glass URL"), blank=True) route_server = LG_URLField(_("Route Server URL"), blank=True) notes = models.TextField(_("Notes"), blank=True) notes_private = models.TextField(_("Private notes"), blank=True) info_traffic = models.CharField(_("Traffic Levels"), max_length=39, blank=True, choices=const.TRAFFIC) info_ratio = models.CharField( _("Traffic Ratios"), max_length=45, blank=True, choices=const.RATIOS, default="Not Disclosed", ) info_scope = models.CharField( _("Geographic Scope"), max_length=39, blank=True, choices=const.SCOPES, default="Not Disclosed", ) info_type = models.CharField( _("Network Type"), max_length=60, blank=True, choices=const.NET_TYPES, default="Not Disclosed", ) info_prefixes4 = models.PositiveIntegerField( _("IPv4 Prefixes"), null=True, blank=True, help_text=_("Recommended maximum number of IPv4 " "routes/prefixes to be configured on peering " "sessions for this ASN"), ) info_prefixes6 = models.PositiveIntegerField( _("IPv6 Prefixes"), null=True, blank=True, help_text=_("Recommended maximum number of IPv6 " "routes/prefixes to be configured on peering " "sessions for this ASN"), ) info_unicast = models.BooleanField(_("Unicast IPv4"), default=False) info_multicast = models.BooleanField(_("Multicast"), default=False) info_ipv6 = models.BooleanField(_("Unicast IPv6"), default=False) info_never_via_route_servers = models.BooleanField( _("Never via route servers"), default=False, help_text=_("Indicates if this network " "will announce its routes " "via route servers or not"), ) policy_url = URLField(_("Peering Policy"), blank=True) policy_general = models.CharField(_("General Policy"), max_length=72, blank=True, choices=const.POLICY_GENERAL) policy_locations = models.CharField( _("Multiple Locations"), max_length=72, blank=True, choices=const.POLICY_LOCATIONS, ) policy_ratio = models.BooleanField(_("Ratio Requirement"), default=False) policy_contracts = models.CharField( _("Contract Requirement"), max_length=36, blank=True, choices=const.POLICY_CONTRACTS, ) status_dashboard = URLField(_("Status Dashboard"), null=True, blank=True) rir_status = models.CharField( _("RIR status"), null=True, default=None, max_length=255, ) rir_status_updated = models.DateTimeField(_("RIR status updated"), blank=True, null=True) class Meta: abstract = True db_table = "%snetwork" % settings.TABLE_PREFIX verbose_name = _("Network") verbose_name_plural = _("Networks") class HandleRef: tag = "net" delete_cascade = ["poc_set", "netfac_set", "netixlan_set"] def __str__(self): return self.name
class NetworkBase(HandleRefModel): asn = ASNField(unique=True) name = models.CharField(max_length=255, unique=True) aka = models.CharField(max_length=255, blank=True) irr_as_set = models.CharField(max_length=255, blank=True, help_text=_("Reference to an AS-SET or " "ROUTE-SET in Internet " "Routing Registry (IRR)")) website = URLField(blank=True) looking_glass = URLField(blank=True) route_server = URLField(blank=True) notes = models.TextField(blank=True) notes_private = models.TextField(blank=True) info_traffic = models.CharField(max_length=39, blank=True, choices=const.TRAFFIC) info_ratio = models.CharField(max_length=45, blank=True, choices=const.RATIOS, default='Not Disclosed') info_scope = models.CharField(max_length=39, blank=True, choices=const.SCOPES, default='Not Disclosed') info_type = models.CharField(max_length=60, blank=True, choices=const.NET_TYPES, default='Not Disclosed') info_prefixes4 = models.PositiveIntegerField( null=True, blank=True, help_text=_("Recommended IPv4 maximum-prefix " "limit to be configured on peering " "sessions for this ASN")) info_prefixes6 = models.PositiveIntegerField( null=True, blank=True, help_text=_("Recommended IPv6 maximum-prefix " "limit to be configured on peering " "sessions for this ASN")) info_unicast = models.BooleanField(default=False) info_multicast = models.BooleanField(default=False) info_ipv6 = models.BooleanField(default=False) info_never_via_route_servers = models.BooleanField( default=False, help_text=_("Indicates if this network " "will announce its routes " "via rout servers or not")) policy_url = URLField(blank=True) policy_general = models.CharField(max_length=72, blank=True, choices=const.POLICY_GENERAL) policy_locations = models.CharField(max_length=72, blank=True, choices=const.POLICY_LOCATIONS) policy_ratio = models.BooleanField(default=False) policy_contracts = models.CharField(max_length=36, blank=True, choices=const.POLICY_CONTRACTS) class Meta: abstract = True db_table = '%snetwork' % settings.TABLE_PREFIX verbose_name_plural = "Networks" class HandleRef: tag = 'net' delete_cascade = ["poc_set", "netfac_set", "netixlan_set"] def __str__(self): return self.name
class Routeserver(HandleRefModel): """ Describes a routeserver at an internet exchange """ ix = models.ForeignKey( InternetExchange, on_delete=models.CASCADE, related_name="rs_set", ) # RS Config name = models.CharField( max_length=255, help_text=_("Routeserver name"), ) asn = ASNField(help_text=_("ASN")) router_id = InetAddressField( store_prefix_length=False, help_text=_("Router Id"), ) rpki_bgp_origin_validation = models.BooleanField(default=False) # ARS Config ars_type = models.CharField( max_length=32, choices=django_ixctl.enum.ARS_TYPES, default="bird", ) max_as_path_length = models.IntegerField( default=32, help_text=_("Max length of AS_PATH attribute."), ) no_export_action = models.CharField( max_length=8, choices=django_ixctl.enum.ARS_NO_EXPORT_ACTIONS, default="pass", help_text=_( "RFC1997 well-known communities (NO_EXPORT and NO_ADVERTISE)"), ) graceful_shutdown = models.BooleanField( default=False, help_text=_("Graceful BGP session shutdown"), ) extra_config = models.TextField(null=True, blank=True, help_text=_("Extra arouteserver config")) class Meta: db_table = "ixctl_rs" unique_together = (("ix", "router_id"), ) class HandleRef: tag = "rs" @property def org(self): return self.ix.instance.org @property def display_name(self): return self.name @property def rsconf(self): """ Return the rsconf instance for this routeserver Will create the rsconf instance if it does not exist yet """ if not hasattr(self, "_rsconf"): rsconf, created = RouteserverConfig.objects.get_or_create(rs=self) self._rsconf = rsconf return self._rsconf @property def rsconf_status_dict(self): """ Returns a status dict for the current state of this routeserver's configuration """ rsconf = self.rsconf task = rsconf.task # no status if not task and not rsconf.rs_response: return {"status": None} if not task: return rsconf.rs_response if task.status == "pending": return {"status": "queued"} if task.status == "running": return {"status": "generating"} if task.status == "cancelled": return {"status": "canceled"} if task.status == "failed": return {"status": "error", "error": task.error} if task.status == "completed": if not rsconf.rs_response: return {"status": "generated"} return rsconf.rs_response return {"status": None} @property def rsconf_status(self): return self.rsconf_status_dict.get("status") @property def rsconf_response(self): return self.rsconf.rs_response @property def rsconf_error(self): return self.rsconf_status_dict.get("error") @property def ars_general(self): """ Generate and return `dict` for ARouteserver general config """ ars_general = { "cfg": { "rs_as": self.asn, "router_id": f"{self.router_id}", "filtering": { "max_as_path_len": self.max_as_path_length, "rpki_bgp_origin_validation": { "enabled": self.rpki_bgp_origin_validation }, }, "rfc1997_wellknown_communities": { "policy": self.no_export_action, }, "graceful_shutdown": { "enabled": self.graceful_shutdown }, } } if self.extra_config: extra_config = yaml.load(self.extra_config, Loader=Loader) # TODO: should we expect people to put the cfg: # root element into the extra config or not ? # # support both approaches for now if "cfg" in extra_config: ars_general["cfg"].update(extra_config["cfg"]) else: ars_general.update(extra_config) return ars_general @property def ars_clients(self): """ Generate and return `dirct` for ARouteserver clients config """ asns = [] asn_as_sets = {} clients = {} # TODO # where to get ASN sets from ?? # peeringdb network ?? rs_peers = InternetExchangeMember.preload_as_macro( self.ix.member_set.filter(is_rs_peer=True)) for member in rs_peers: if member.asn not in asns: asns.append(member.asn) if member.asn not in clients: clients[member.asn] = {"asn": member.asn, "ip": [], "cfg": {}} if member.ipaddr4: clients[member.asn]["ip"].append(f"{member.ipaddr4}") if member.ipaddr6: clients[member.asn]["ip"].append(f"{member.ipaddr6}") if member.as_macro: clients[member.asn]["cfg"].update( filtering={"irrdb": { "as_sets": member.as_sets, }}) if asns: for net in pdbctl.Network().objects(asns=asns): as_set = get_as_set(net) if as_set: asn_as_sets[f"AS{net.asn}"] = {"as_sets": [as_set]} print(asn_as_sets) return {"asns": asn_as_sets, "clients": list(clients.values())} def __str__(self): return f"Routeserver {self.name} AS{self.asn}"