import project

This commit is contained in:
Chevallier
2026-01-08 13:51:16 +01:00
commit df6334febc
40 changed files with 17440 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
# Firewall Config Parser & Excel Flow Matrix Generator
## Description
Cet outil permet de **parser les configurations de différents types de firewalls** (Palo Alto, Stormshield, Forcepoint) et de **convertir ces informations en un format JSON normalisé basé sur des modèles OpenConfig en YANG**.
Il fournit également la possibilité de générer une **matrice de flux au format Excel** pour visualiser les communications et règles de trafic dans linfrastructure.
## Fonctionnalités principales
1. **Analyse multi-firewalls**
- Développement de scripts Python dédiés à chaque type de firewall :
- Palo Alto
- Stormshield
- Forcepoint
- Extraction automatique des informations pertinentes à partir des fichiers de configuration respectifs.
- address
- address-group
- service
- service-group
- interface
- rules
- routes
2. **Modèle YANG personnalisé**
- Conception dun modèle YANG personnalisé pour stocker les informations spécifiques non couvertes par OpenConfig :
- `address`
- `address-group`
- `service`
- `service-group`
3. **Conversion en JSON normalisé**
- Export des configurations dans un format JSON structuré selon les modèles OpenConfig :
- `openconfig-acl`
- `openconfig-interfaces`
- `openconfig-network-instance`
- Intégration des objets personnalisés via le modèle YANG développé.
5. **Génération de matrices de flux**
- Script Python qui utilise le JSON normalisé pour générer automatiquement une matrice Excel détaillant :
- les règles de sécurité
- les communications entre objets et groupes dadresses/services.
## Utilisation
### Pré-requis
```bash
python -m venv .venv
.\.venv\Scripts\activate
pip install -r .\src\requierements.txt
```
- Mettre le/les fichier(s) de configurations dans le dossier `/src/input/`
- Modifier le fichier `site.json` de données dans `/src/data/`
#### Commandes principales
```bash
python3 .\src\main.py stormshield .\src\input\backup\ -m
python3 .\src\main.py paloalto .\src\input\nomfichier -m
python3 .\src\main.py forcepoint .\src\input\nomfichier -m
```
#### Options
| Option | Description |
|--------|-------------|
| -o [nom_fichier] | Spécifie le nom du fichier JSON de sortie (optionnel)
| -m | Génère un rapport Excel de type matrice de flux (optionnel)
---
## Arborescence du projet
```bash
C:.
├───src
│ ├───data # Données static
│ ├───input # Fichiers/Dossiers de configuration
│ ├───modèles # Modèles YANG
│ ├───output # Fichiers JSON normalisés/Excel matrice de flux
│ └───scripts # Fichiers python
│ ├───objets
│ └───style_excel
```
## Structure du JSON généré
```bash
.json
├── firewall-device # type de firewall (palo-alto|stormshield|forcepoint)
├── openconfig-interfaces
├── openconfig-network-instances
├── openconfig-acl
└── custom-firewall-objects
├── address
├── address-group
├── service
└── service-group
```
## Fichiers YANG utilisés
| Fichier YANG | Description |
|--------------|-------------|
| `.\src\modèles\openconfig-acl.yang` | Décrit les ACL et règles de firewall standard OpenConfig |
| `.\src\modèles\openconfig-interfaces.yang` | Modèle pour les interfaces réseau standard OpenConfig |
| `.\src\modèles\openconfig-network-instance.yang` | Modèle pour les VRF / instances réseau OpenConfig |
| `.\src\modèles\custom-firewall-objects.yang` | Modèle personnalisé pour les objets spécifiques (address, address-group, service, service-group) |
---
## Auteurs
Projet développé par :
- Julie Chevallier | Computacenter

View File

@@ -0,0 +1,2 @@
pandas>=2.3.1
openpyxl>=3.1.5

View File

@@ -0,0 +1,6 @@
{
"10.0.2.0/24": "ZONE1",
"10.0.3.0/24": "ZONE2",
"30.20.0.0/16": "ZONE3",
"30.30.0.0/16": "ZONE4"
}

View File

@@ -0,0 +1,61 @@
import sys
import os
import time
from scripts.json_PaloAlto import generate_json_paloalto
from scripts.json_Stormshield import generate_json_stormshield
from scripts.json_Forcepoint import generate_json_forcepoint
from scripts.export_excel import export_to_excel
def main():
if len(sys.argv) < 3:
print("Usage: python3 src/main.py <firewall_type>[paloalto|stormshield|forcepoint] <input_directory/file> [-o <output_file>] [-m]")
print("Options:")
print(" <firewall_type> Type of firewall to process (paloalto|stormshield|forcepoint)")
print(" -o <output_file> Specify output JSON file name (optional)")
print(" -m Generate Excel report (optional)")
sys.exit(1)
firewall_type = sys.argv[1].lower()
input_data = sys.argv[2]
output_path = "src/output/"
if "-o" in sys.argv:
o_index = sys.argv.index("-o")
if o_index + 1 < len(sys.argv):
output_file_json = f"{output_path}{firewall_type}_{sys.argv[o_index + 1]}.json"
else:
print("Erreur: nom de fichier de sortie manquant après '-o'.")
sys.exit(1)
else:
timestamp = time.strftime("%Y%m%d")
output_file_json = f"{output_path}{firewall_type}_{timestamp}.json"
os.makedirs(output_path, exist_ok=True)
if firewall_type == "paloalto":
generate_json_paloalto(input_data, output_file_json)
elif firewall_type == "stormshield":
generate_json_stormshield(input_data, output_file_json)
elif firewall_type == "forcepoint":
generate_json_forcepoint(input_data, output_file_json)
else:
print("Erreur: type de firewall inconnu. Utilisez 'paloalto', 'stormshield' ou 'forcepoint'.")
sys.exit(1)
if "-m" in sys.argv:
print(f"\nGénération de l'export Excel...")
if "-o" in sys.argv:
o_index = sys.argv.index("-o")
if o_index + 1 < len(sys.argv):
output_file_excel = os.path.join(f"{output_path}matrice_{firewall_type}_{sys.argv[o_index + 1]}.xlsx")
else:
print("Erreur: nom de fichier de sortie manquant après '-o'.")
sys.exit(1)
else:
timestamp = time.strftime("%Y%m%d")
output_file_excel = f"{output_path}matrice_{firewall_type}_{timestamp}.xlsx"
excel_file = export_to_excel(output_file_json, output_file_excel)
print(f"✓ Processus terminé. Fichiers générés:\n - JSON: {output_file_json}\n - Excel: {excel_file}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,108 @@
module custom-firewall-objects {
yang-version 1.1;
namespace "urn:custom:firewall-objects";
prefix cfwobj;
import ietf-inet-types { prefix inet; }
import firewall-device { prefix fwd; }
organization "Custom Network Automation";
contact "Julie Chevallier";
description
"Custom firewall objects model depending on the firewall type.";
revision "2025-12-12" {
description "Initial version with conditional structure.";
reference "Internal reference FW-OBJ-001.";
}
container firewall-objects {
description
"Firewall object definitions depending on firewall type.";
choice vendor-type {
description "Different structures depending on the firewall device type.";
case palo-alto {
when "/fwd:firewall-device/fwd:type = 'palo-alto'";
description "Objects for Palo Alto firewalls.";
container palo-alto-objects {
description "Container for Palo Alto specific objects.";
list address {
key "name";
description "Palo Alto address objects.";
leaf name { type string; description "Object name."; }
leaf-list members { type string; description "Members list."; }
leaf description { type string; description "Description."; }
leaf tag { type string; description "Tag."; }
}
list address-group {
key "name";
description "Palo Alto address groups.";
leaf name { type string; description "Group name."; }
leaf-list ip_netmask { type string; description "IP/netmask list."; }
leaf description { type string; description "Description."; }
leaf tag { type string; description "Tag."; }
}
list service {
key "name";
description "Palo Alto service objects.";
leaf name { type string; description "Service name."; }
leaf protocol { type string; description "Protocol."; }
leaf port { type string; description "Port number or range."; }
leaf source_port { type string; description "Source port."; }
leaf description { type string; description "Description."; }
leaf tag { type string; description "Tag."; }
}
list service-group {
key "name";
description "Palo Alto service groups.";
leaf name { type string; description "Group name."; }
leaf-list members { type string; description "Members list."; }
leaf description { type string; description "Description."; }
leaf tag { type string; description "Tag."; }
}
}
}
case fortinet {
when "/fwd:firewall-device/fwd:type = 'fortinet'";
description "Objects for Fortinet firewalls.";
container fortinet-objects {
description "Container for Fortinet specific objects.";
list address {
key "name";
description "Fortinet address objects.";
leaf name { type string; description "Object name."; }
leaf subnet { type inet:ipv4-prefix; description "IPv4 subnet."; }
leaf interface { type string; description "Associated interface."; }
leaf comment { type string; description "Description or comment."; }
}
list service {
key "name";
description "Fortinet service objects.";
leaf name { type string; description "Service name."; }
leaf protocol {
type enumeration {
enum TCP { description "TCP protocol."; }
enum UDP { description "UDP protocol."; }
}
description "Protocol type.";
}
leaf tcp_portrange { type string; description "TCP port range."; }
leaf udp_portrange { type string; description "UDP port range."; }
leaf comment { type string; description "Description or comment."; }
}
}
}
}
}
}

View File

@@ -0,0 +1,34 @@
module firewall-device {
yang-version 1.1;
namespace "urn:custom:firewall-device";
prefix fwd;
organization "Custom Network Automation";
contact "Julie Chevallier";
description
"Simple device info model exposing firewall vendor type.";
revision "2025-12-12" {
description
"Initial version of the firewall device type module.";
reference
"Internal reference FW-DEV-001.";
}
container firewall-device {
description
"Container representing the firewall vendor and type.";
leaf type {
type enumeration {
enum palo-alto {
description "Palo Alto Networks firewall.";
}
enum fortinet {
description "Fortinet firewall.";
}
}
description "Firewall vendor type.";
}
}
}

View File

@@ -0,0 +1,669 @@
module ietf-inet-types {
namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
prefix "inet";
organization
"IETF Network Modeling (NETMOD) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
Editor: Juergen Schoenwaelder
<mailto:jschoenwaelder@constructor.university>";
description
"This module contains a collection of generally useful derived
YANG data types for Internet addresses and related things.
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
'MAY', and 'OPTIONAL' in this document are to be interpreted as
described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
they appear in all capitals, as shown here.
Copyright (c) 2025 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Revised BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC XXXX;
see the RFC itself for full legal notices.";
revision 2025-06-23 {
description
"This revision adds the following new data types:
- inet:ip-address-and-prefix
- inet:ipv4-address-and-prefix
- inet:ipv6-address-and-prefix
- inet:protocol-number
- inet:upper-layer-protocol-number
- inet:host-name
- inet:email-address
- inet:ip-address-link-local
- inet:ipv4-address-link-local
- inet:ipv6-address-link-local
The inet:host union was changed to use inet:host-name instead
of inet:domain-name. Several pattern statements have been
improved.";
reference
"RFC XXXX: Common YANG Data Types";
}
revision 2013-07-15 {
description
"This revision adds the following new data types:
- inet:ip-address-no-zone
- inet:ipv4-address-no-zone
- inet:ipv6-address-no-zone";
reference
"RFC 6991: Common YANG Data Types";
}
revision 2010-09-24 {
description
"Initial revision.";
reference
"RFC 6021: Common YANG Data Types";
}
/*** collection of types related to protocol fields ***/
typedef ip-version {
type enumeration {
enum unknown {
value "0";
description
"An unknown or unspecified version of the Internet
protocol.";
}
enum ipv4 {
value "1";
description
"The IPv4 protocol as defined in RFC 791.";
}
enum ipv6 {
value "2";
description
"The IPv6 protocol as defined in RFC 8200.";
}
}
description
"This value represents the version of the IP protocol.
In the value set and its semantics, this type is equivalent
to the InetVersion textual convention of the SMIv2.";
reference
"RFC 791: Internet Protocol
RFC 8200: Internet Protocol, Version 6 (IPv6) Specification
RFC 4001: Textual Conventions for Internet Network Addresses";
}
typedef dscp {
type uint8 {
range "0..63";
}
description
"The dscp type represents a Differentiated Services Code Point
that may be used for marking packets in a traffic stream.
In the value set and its semantics, this type is equivalent
to the Dscp textual convention of the SMIv2.";
reference
"RFC 3289: Management Information Base for the Differentiated
Services Architecture
RFC 2474: Definition of the Differentiated Services Field
(DS Field) in the IPv4 and IPv6 Headers
RFC 2780: IANA Allocation Guidelines For Values In
the Internet Protocol and Related Headers";
}
typedef ipv6-flow-label {
type uint32 {
range "0..1048575";
}
description
"The ipv6-flow-label type represents the flow identifier or
Flow Label in an IPv6 packet header that may be used to
discriminate traffic flows.
In the value set and its semantics, this type is equivalent
to the IPv6FlowLabel textual convention of the SMIv2.";
reference
"RFC 3595: Textual Conventions for IPv6 Flow Label
RFC 8200: Internet Protocol, Version 6 (IPv6) Specification";
}
typedef port-number {
type uint16 {
range "0..65535";
}
description
"The port-number type represents a 16-bit port number of an
Internet transport-layer protocol such as UDP, TCP, DCCP, or
SCTP.
Port numbers are assigned by IANA. The current list of
all assignments is available from <https://www.iana.org/>.
Note that the port number value zero is reserved by IANA. In
situations where the value zero does not make sense, it can
be excluded by subtyping the port-number type.
In the value set and its semantics, this type is equivalent
to the InetPortNumber textual convention of the SMIv2.";
reference
"RFC 768: User Datagram Protocol
RFC 9293: Transmission Control Protocol (TCP)
RFC 9260: Stream Control Transmission Protocol
RFC 4340: Datagram Congestion Control Protocol (DCCP)
RFC 4001: Textual Conventions for Internet Network Addresses";
}
typedef protocol-number {
type uint8;
description
"The protocol-number type represents an 8-bit Internet
protocol number, carried in the 'protocol' field of the
IPv4 header or in the 'next header' field of the IPv6
header.
Protocol numbers are assigned by IANA. The current list of
all assignments is available from <https://www.iana.org/>.";
reference
"RFC 791: Internet Protocol
RFC 8200: Internet Protocol, Version 6 (IPv6) Specification";
}
typedef upper-layer-protocol-number {
type protocol-number;
description
"The upper-layer-protocol-number represents the upper-layer
protocol number carried in an IP packet. For IPv6 packets
with extension headers, this is the protocol number carried
in the last 'next header' field of the chain of IPv6 extension
headers.";
reference
"RFC 791: Internet Protocol
RFC 8200: Internet Protocol, Version 6 (IPv6) Specification";
}
/*** collection of types related to autonomous systems ***/
typedef as-number {
type uint32;
description
"The as-number type represents autonomous system numbers
which identify an Autonomous System (AS). An AS is a set
of routers under a single technical administration, using
an interior gateway protocol and common metrics to route
packets within the AS, and using an exterior gateway
protocol to route packets to other ASes. IANA maintains
the AS number space and has delegated large parts to the
regional registries.
Autonomous system numbers were originally limited to 16
bits. BGP extensions have enlarged the autonomous system
number space to 32 bits. This type therefore uses an uint32
base type without a range restriction in order to support
a larger autonomous system number space.
In the value set and its semantics, this type is equivalent
to the InetAutonomousSystemNumber textual convention of
the SMIv2.";
reference
"RFC 1930: Guidelines for creation, selection, and registration
of an Autonomous System (AS)
RFC 4271: A Border Gateway Protocol 4 (BGP-4)
RFC 4001: Textual Conventions for Internet Network Addresses
RFC 6793: BGP Support for Four-Octet Autonomous System (AS)
Number Space";
}
/*** collection of types related to IP addresses and hostnames ***/
typedef ip-address {
type union {
type ipv4-address;
type ipv6-address;
}
description
"The ip-address type represents an IP address and is IP
version neutral. The format of the textual representation
implies the IP version. This type supports scoped addresses
by allowing zone identifiers in the address format.";
reference
"RFC 4007: IPv6 Scoped Address Architecture";
}
typedef ipv4-address {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '(%.+)?';
}
description
"The ipv4-address type represents an IPv4 address in
dotted-quad notation. The IPv4 address may include a zone
index, separated by a % sign. If a system uses zone names
that are not represented in UTF-8, then an implementation
needs to use some mechanism to transform the local name
into UTF-8. The definition of such a mechanism is outside
the scope of this document.
The zone index is used to disambiguate identical address
values. For link-local addresses, the zone index will
typically be the interface index number or the name of an
interface. If the zone index is not present, the default
zone of the device will be used.
The canonical format for the zone index is the numerical
format";
}
typedef ipv6-address {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(%[A-Za-z0-9][A-Za-z0-9\-\._~/]*)?';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(%.+)?';
}
description
"The ipv6-address type represents an IPv6 address in full,
mixed, shortened, and shortened-mixed notation. The IPv6
address may include a zone index, separated by a % sign.
If a system uses zone names that are not represented in
UTF-8, then an implementation needs to use some mechanism
to transform the local name into UTF-8. The definition of
such a mechanism is outside the scope of this document.
The zone index is used to disambiguate identical address
values. For link-local addresses, the zone index will
typically be the interface index number or the name of an
interface. If the zone index is not present, the default
zone of the device will be used.
The canonical format of IPv6 addresses uses the textual
representation defined in Section 4 of RFC 5952. The
canonical format for the zone index is the numerical
format as described in Section 11.2 of RFC 4007.";
reference
"RFC 4291: IP Version 6 Addressing Architecture
RFC 4007: IPv6 Scoped Address Architecture
RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
typedef ip-address-no-zone {
type union {
type ipv4-address-no-zone;
type ipv6-address-no-zone;
}
description
"The ip-address-no-zone type represents an IP address and is
IP version neutral. The format of the textual representation
implies the IP version. This type does not support scoped
addresses since it does not allow zone identifiers in the
address format.";
reference
"RFC 4007: IPv6 Scoped Address Architecture";
}
typedef ipv4-address-no-zone {
type ipv4-address {
pattern '[0-9\.]*';
}
description
"An IPv4 address without a zone index. This type, derived
from the type ipv4-address, may be used in situations where
the zone is known from the context and no zone index is
needed.";
}
typedef ipv6-address-no-zone {
type ipv6-address {
pattern '[0-9a-fA-F:\.]*';
}
description
"An IPv6 address without a zone index. This type, derived
from the type ipv6-address, may be used in situations where
the zone is known from the context and no zone index is
needed.";
reference
"RFC 4291: IP Version 6 Addressing Architecture
RFC 4007: IPv6 Scoped Address Architecture
RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
typedef ip-address-link-local {
type union {
type ipv4-address-link-local;
type ipv6-address-link-local;
}
description
"The ip-address-link-local type represents a link-local IP
address and is IP version neutral. The format of the textual
representation implies the IP version.";
}
typedef ipv4-address-link-local {
type ipv4-address {
pattern '169\.254\..*';
}
description
"A link-local IPv4 address in the prefix 169.254.0.0/16 as
defined in section 2.1. of RFC 3927.";
reference
"RFC 3927: Dynamic Configuration of IPv4 Link-Local Addresses";
}
typedef ipv6-address-link-local {
type ipv6-address {
pattern '[fF][eE]80:.*';
}
description
"A link-local IPv6 address in the prefix fe80::/10 as defined
in section 2.5.6. of RFC 4291.";
reference
"RFC 4291: IP Version 6 Addressing Architecture";
}
typedef ip-prefix {
type union {
type ipv4-prefix;
type ipv6-prefix;
}
description
"The ip-prefix type represents an IP prefix and is IP
version neutral. The format of the textual representations
implies the IP version.";
}
typedef ipv4-prefix {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '/(([0-9])|([1-2][0-9])|(3[0-2]))';
}
description
"The ipv4-prefix type represents an IPv4 prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 32.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.
The canonical format of an IPv4 prefix has all bits of
the IPv4 address set to zero that are not part of the
IPv4 prefix.
The definition of ipv4-prefix does not require that bits,
which are not part of the prefix, are set to zero. However,
implementations have to return values in canonical format,
which requires non-prefix bits to be set to zero. This means
that 192.0.2.1/24 must be accepted as a valid value but it
will be converted into the canonical format 192.0.2.0/24.";
}
typedef ipv6-prefix {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(/.+)';
}
description
"The ipv6-prefix type represents an IPv6 prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 128.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.
The canonical format of an IPv6 prefix has all bits of
the IPv6 address set to zero that are not part of the
IPv6 prefix. Furthermore, the IPv6 address is represented
as defined in Section 4 of RFC 5952.
The definition of ipv6-prefix does not require that bits,
which are not part of the prefix, are set to zero. However,
implementations have to return values in canonical format,
which requires non-prefix bits to be set to zero. This means
that 2001:db8::1/64 must be accepted as a valid value but it
will be converted into the canonical format 2001:db8::/64.";
reference
"RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
typedef ip-address-and-prefix {
type union {
type ipv4-address-and-prefix;
type ipv6-address-and-prefix;
}
description
"The ip-address-and-prefix type represents an IP address and
prefix and is IP version neutral. The format of the textual
representations implies the IP version.";
}
typedef ipv4-address-and-prefix {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '/(([0-9])|([1-2][0-9])|(3[0-2]))';
}
description
"The ipv4-address-and-prefix type represents an IPv4
address and an associated IPv4 prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 32.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.";
}
typedef ipv6-address-and-prefix {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(/.+)';
}
description
"The ipv6-address-and-prefix type represents an IPv6
address and an associated IPv6 prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 128.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.
The canonical format requires that the IPv6 address is
represented as defined in Section 4 of RFC 5952.";
reference
"RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
/*** collection of domain name and URI types ***/
typedef domain-name {
type string {
length "1..253";
pattern
'((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ '|\.';
}
description
"The domain-name type represents a DNS domain name. The
name SHOULD be fully qualified whenever possible. This
type does not support wildcards (see RFC 4592) or
classless in-addr.arpa delegations (see RFC 2317).
Internet domain names are only loosely specified. Section
3.5 of RFC 1034 recommends a syntax (modified in Section
2.1 of RFC 1123). The pattern above is intended to allow
for current practice in domain name use, and some possible
future expansion. Note that Internet host names have a
stricter syntax (described in RFC 952) than the DNS
recommendations in RFCs 1034 and 1123. Schema nodes
representing host names should use the host-name type
instead of the domain-type.
The encoding of DNS names in the DNS protocol is limited
to 255 characters. Since the encoding consists of labels
prefixed by a length bytes and there is a trailing NULL
byte, only 253 characters can appear in the textual dotted
notation.
The description clause of schema nodes using the domain-name
type MUST describe when and how these names are resolved to
IP addresses. Note that the resolution of a domain-name value
may require to query multiple DNS records (e.g., A for IPv4
and AAAA for IPv6). The order of the resolution process and
which DNS record takes precedence can either be defined
explicitly or may depend on the configuration of the
resolver.
Domain-name values use the US-ASCII encoding. Their canonical
format uses lowercase US-ASCII characters. Internationalized
domain names MUST be A-labels as per RFC 5890.";
reference
"RFC 952: DoD Internet Host Table Specification
RFC 1034: Domain Names - Concepts and Facilities
RFC 1123: Requirements for Internet Hosts -- Application
and Support
RFC 2317: Classless IN-ADDR.ARPA delegation
RFC 2782: A DNS RR for specifying the location of services
(DNS SRV)
RFC 4592: The Role of Wildcards in the Domain Name System
RFC 5890: Internationalized Domain Names in Applications
(IDNA): Definitions and Document Framework
RFC 9499: DNS Terminology";
}
typedef host-name {
type domain-name {
length "2..max";
pattern '[a-zA-Z0-9\-\.]+';
}
description
"The host-name type represents (fully qualified) host names.
Host names must be at least two characters long (see RFC 952)
and they are restricted to labels consisting of letters, digits
and hyphens separated by dots (see RFC1123 and RFC 952).";
reference
"RFC 952: DoD Internet Host Table Specification
RFC 1123: Requirements for Internet Hosts -- Application
and Support";
}
typedef host {
type union {
type ip-address;
type host-name;
}
description
"The host type represents either an IP address or a (fully
qualified) host name.";
}
typedef uri {
type string {
pattern '[a-z][a-z0-9+.-]*:.*';
}
description
"The uri type represents a Uniform Resource Identifier
(URI) as defined by the rule 'URI' in RFC 3986.
Objects using the uri type MUST be in US-ASCII encoding,
and MUST be normalized as described by RFC 3986 Sections
6.2.1, 6.2.2.1, and 6.2.2.2. Characters that can be
represented without using percent-encoding are represented
as characters (without percent-encoding), and all
case-insensitive characters are set to lowercase except
for hexadecimal digits within a percent-encoded triplet,
which are normalized to uppercase as described in
Section 6.2.2.1 of RFC 3986.
The purpose of this normalization is to help provide
unique URIs. Note that this normalization is not
sufficient to provide uniqueness. Two URIs that are
textually distinct after this normalization may still be
equivalent.
Objects using the uri type may restrict the schemes that
they permit. For example, 'data:' and 'urn:' schemes
might not be appropriate.
A zero-length URI is not a valid URI. This can be used to
express 'URI absent' where required.
In the value set and its semantics, this type is equivalent
to the Uri SMIv2 textual convention defined in RFC 5017.";
reference
"RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
Group: Uniform Resource Identifiers (URIs), URLs,
and Uniform Resource Names (URNs): Clarifications
and Recommendations
RFC 5017: MIB Textual Conventions for Uniform Resource
Identifiers (URIs)";
}
typedef email-address {
type string {
pattern '.+@.+';
}
description
"The email-address type represents an internationalized
email address.
The email address format is defined by the addr-spec
ABNF rule in RFC 5322 section 3.4.1. This format has
been extended by RFC 6532 to support internationalized
email addresses. Implementations MUST support the
internationalization extensions of RFC 6532. Support
of the obsolete obs-local-part, obs-domain, and
obs-qtext parts of RFC 5322 is not required.
The domain part may use both A-labels and U-labels
(see RFC 5890). The canonical format of the domain part
uses lowercase characters and U-labels (RFC 5890) where
applicable.";
reference
"RFC 5322: Internet Message Format
RFC 5890: Internationalized Domain Names in Applications
(IDNA): Definitions and Document Framework
RFC 6531: SMTP Extension for Internationalized Email";
}
}

View File

@@ -0,0 +1,725 @@
module ietf-interfaces {
namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
prefix if;
import ietf-yang-types {
prefix yang;
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: Thomas Nadeau
<mailto:tnadeau@lucidvision.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Martin Bjorklund
<mailto:mbj@tail-f.com>";
description
"This module contains a collection of YANG definitions for
managing network interfaces.
Copyright (c) 2014 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 7223; see
the RFC itself for full legal notices.";
revision 2014-05-08 {
description
"Initial revision.";
reference
"RFC 7223: A YANG Data Model for Interface Management";
}
/*
* Typedefs
*/
typedef interface-ref {
type leafref {
path "/if:interfaces/if:interface/if:name";
}
description
"This type is used by data models that need to reference
configured interfaces.";
}
typedef interface-state-ref {
type leafref {
path "/if:interfaces-state/if:interface/if:name";
}
description
"This type is used by data models that need to reference
the operationally present interfaces.";
}
/*
* Identities
*/
identity interface-type {
description
"Base identity from which specific interface types are
derived.";
}
/*
* Features
*/
feature arbitrary-names {
description
"This feature indicates that the device allows user-controlled
interfaces to be named arbitrarily.";
}
feature pre-provisioning {
description
"This feature indicates that the device supports
pre-provisioning of interface configuration, i.e., it is
possible to configure an interface whose physical interface
hardware is not present on the device.";
}
feature if-mib {
description
"This feature indicates that the device implements
the IF-MIB.";
reference
"RFC 2863: The Interfaces Group MIB";
}
/*
* Configuration data nodes
*/
container interfaces {
description
"Interface configuration parameters.";
list interface {
key "name";
description
"The list of configured interfaces on the device.
The operational state of an interface is available in the
/interfaces-state/interface list. If the configuration of a
system-controlled interface cannot be used by the system
(e.g., the interface hardware present does not match the
interface type), then the configuration is not applied to
the system-controlled interface shown in the
/interfaces-state/interface list. If the configuration
of a user-controlled interface cannot be used by the system,
the configured interface is not instantiated in the
/interfaces-state/interface list.";
leaf name {
type string;
description
"The name of the interface.
A device MAY restrict the allowed values for this leaf,
possibly depending on the type of the interface.
For system-controlled interfaces, this leaf is the
device-specific name of the interface. The 'config false'
list /interfaces-state/interface contains the currently
existing interfaces on the device.
If a client tries to create configuration for a
system-controlled interface that is not present in the
/interfaces-state/interface list, the server MAY reject
the request if the implementation does not support
pre-provisioning of interfaces or if the name refers to
an interface that can never exist in the system. A
NETCONF server MUST reply with an rpc-error with the
error-tag 'invalid-value' in this case.
If the device supports pre-provisioning of interface
configuration, the 'pre-provisioning' feature is
advertised.
If the device allows arbitrarily named user-controlled
interfaces, the 'arbitrary-names' feature is advertised.
When a configured user-controlled interface is created by
the system, it is instantiated with the same name in the
/interface-state/interface list.";
}
leaf description {
type string;
description
"A textual description of the interface.
A server implementation MAY map this leaf to the ifAlias
MIB object. Such an implementation needs to use some
mechanism to handle the differences in size and characters
allowed between this leaf and ifAlias. The definition of
such a mechanism is outside the scope of this document.
Since ifAlias is defined to be stored in non-volatile
storage, the MIB implementation MUST map ifAlias to the
value of 'description' in the persistently stored
datastore.
Specifically, if the device supports ':startup', when
ifAlias is read the device MUST return the value of
'description' in the 'startup' datastore, and when it is
written, it MUST be written to the 'running' and 'startup'
datastores. Note that it is up to the implementation to
decide whether to modify this single leaf in 'startup' or
perform an implicit copy-config from 'running' to
'startup'.
If the device does not support ':startup', ifAlias MUST
be mapped to the 'description' leaf in the 'running'
datastore.";
reference
"RFC 2863: The Interfaces Group MIB - ifAlias";
}
leaf type {
type identityref {
base interface-type;
}
mandatory true;
description
"The type of the interface.
When an interface entry is created, a server MAY
initialize the type leaf with a valid value, e.g., if it
is possible to derive the type from the name of the
interface.
If a client tries to set the type of an interface to a
value that can never be used by the system, e.g., if the
type is not supported or if the type does not match the
name of the interface, the server MUST reject the request.
A NETCONF server MUST reply with an rpc-error with the
error-tag 'invalid-value' in this case.";
reference
"RFC 2863: The Interfaces Group MIB - ifType";
}
leaf enabled {
type boolean;
default "true";
description
"This leaf contains the configured, desired state of the
interface.
Systems that implement the IF-MIB use the value of this
leaf in the 'running' datastore to set
IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
has been initialized, as described in RFC 2863.
Changes in this leaf in the 'running' datastore are
reflected in ifAdminStatus, but if ifAdminStatus is
changed over SNMP, this leaf is not affected.";
reference
"RFC 2863: The Interfaces Group MIB - ifAdminStatus";
}
leaf link-up-down-trap-enable {
if-feature if-mib;
type enumeration {
enum enabled {
value 1;
}
enum disabled {
value 2;
}
}
description
"Controls whether linkUp/linkDown SNMP notifications
should be generated for this interface.
If this node is not configured, the value 'enabled' is
operationally used by the server for interfaces that do
not operate on top of any other interface (i.e., there are
no 'lower-layer-if' entries), and 'disabled' otherwise.";
reference
"RFC 2863: The Interfaces Group MIB -
ifLinkUpDownTrapEnable";
}
}
}
/*
* Operational state data nodes
*/
container interfaces-state {
config false;
description
"Data nodes for the operational state of interfaces.";
list interface {
key "name";
description
"The list of interfaces on the device.
System-controlled interfaces created by the system are
always present in this list, whether they are configured or
not.";
leaf name {
type string;
description
"The name of the interface.
A server implementation MAY map this leaf to the ifName
MIB object. Such an implementation needs to use some
mechanism to handle the differences in size and characters
allowed between this leaf and ifName. The definition of
such a mechanism is outside the scope of this document.";
reference
"RFC 2863: The Interfaces Group MIB - ifName";
}
leaf type {
type identityref {
base interface-type;
}
mandatory true;
description
"The type of the interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifType";
}
leaf admin-status {
if-feature if-mib;
type enumeration {
enum up {
value 1;
description
"Ready to pass packets.";
}
enum down {
value 2;
description
"Not ready to pass packets and not in some test mode.";
}
enum testing {
value 3;
description
"In some test mode.";
}
}
mandatory true;
description
"The desired state of the interface.
This leaf has the same read semantics as ifAdminStatus.";
reference
"RFC 2863: The Interfaces Group MIB - ifAdminStatus";
}
leaf oper-status {
type enumeration {
enum up {
value 1;
description
"Ready to pass packets.";
}
enum down {
value 2;
description
"The interface does not pass any packets.";
}
enum testing {
value 3;
description
"In some test mode. No operational packets can
be passed.";
}
enum unknown {
value 4;
description
"Status cannot be determined for some reason.";
}
enum dormant {
value 5;
description
"Waiting for some external event.";
}
enum not-present {
value 6;
description
"Some component (typically hardware) is missing.";
}
enum lower-layer-down {
value 7;
description
"Down due to state of lower-layer interface(s).";
}
}
mandatory true;
description
"The current operational state of the interface.
This leaf has the same semantics as ifOperStatus.";
reference
"RFC 2863: The Interfaces Group MIB - ifOperStatus";
}
leaf last-change {
type yang:date-and-time;
description
"The time the interface entered its current operational
state. If the current state was entered prior to the
last re-initialization of the local network management
subsystem, then this node is not present.";
reference
"RFC 2863: The Interfaces Group MIB - ifLastChange";
}
leaf if-index {
if-feature if-mib;
type int32 {
range "1..2147483647";
}
mandatory true;
description
"The ifIndex value for the ifEntry represented by this
interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifIndex";
}
leaf phys-address {
type yang:phys-address;
description
"The interface's address at its protocol sub-layer. For
example, for an 802.x interface, this object normally
contains a Media Access Control (MAC) address. The
interface's media-specific modules must define the bit
and byte ordering and the format of the value of this
object. For interfaces that do not have such an address
(e.g., a serial line), this node is not present.";
reference
"RFC 2863: The Interfaces Group MIB - ifPhysAddress";
}
leaf-list higher-layer-if {
type interface-state-ref;
description
"A list of references to interfaces layered on top of this
interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifStackTable";
}
leaf-list lower-layer-if {
type interface-state-ref;
description
"A list of references to interfaces layered underneath this
interface.";
reference
"RFC 2863: The Interfaces Group MIB - ifStackTable";
}
leaf speed {
type yang:gauge64;
units "bits/second";
description
"An estimate of the interface's current bandwidth in bits
per second. For interfaces that do not vary in
bandwidth or for those where no accurate estimation can
be made, this node should contain the nominal bandwidth.
For interfaces that have no concept of bandwidth, this
node is not present.";
reference
"RFC 2863: The Interfaces Group MIB -
ifSpeed, ifHighSpeed";
}
container statistics {
description
"A collection of interface-related statistics objects.";
leaf discontinuity-time {
type yang:date-and-time;
mandatory true;
description
"The time on the most recent occasion at which any one or
more of this interface's counters suffered a
discontinuity. If no such discontinuities have occurred
since the last re-initialization of the local management
subsystem, then this node contains the time the local
management subsystem re-initialized itself.";
}
leaf in-octets {
type yang:counter64;
description
"The total number of octets received on the interface,
including framing characters.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCInOctets";
}
leaf in-unicast-pkts {
type yang:counter64;
description
"The number of packets, delivered by this sub-layer to a
higher (sub-)layer, that were not addressed to a
multicast or broadcast address at this sub-layer.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
}
leaf in-broadcast-pkts {
type yang:counter64;
description
"The number of packets, delivered by this sub-layer to a
higher (sub-)layer, that were addressed to a broadcast
address at this sub-layer.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCInBroadcastPkts";
}
leaf in-multicast-pkts {
type yang:counter64;
description
"The number of packets, delivered by this sub-layer to a
higher (sub-)layer, that were addressed to a multicast
address at this sub-layer. For a MAC-layer protocol,
this includes both Group and Functional addresses.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCInMulticastPkts";
}
leaf in-discards {
type yang:counter32;
description
"The number of inbound packets that were chosen to be
discarded even though no errors had been detected to
prevent their being deliverable to a higher-layer
protocol. One possible reason for discarding such a
packet could be to free up buffer space.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifInDiscards";
}
leaf in-errors {
type yang:counter32;
description
"For packet-oriented interfaces, the number of inbound
packets that contained errors preventing them from being
deliverable to a higher-layer protocol. For character-
oriented or fixed-length interfaces, the number of
inbound transmission units that contained errors
preventing them from being deliverable to a higher-layer
protocol.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifInErrors";
}
leaf in-unknown-protos {
type yang:counter32;
description
"For packet-oriented interfaces, the number of packets
received via the interface that were discarded because
of an unknown or unsupported protocol. For
character-oriented or fixed-length interfaces that
support protocol multiplexing, the number of
transmission units received via the interface that were
discarded because of an unknown or unsupported protocol.
For any interface that does not support protocol
multiplexing, this counter is not present.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
}
leaf out-octets {
type yang:counter64;
description
"The total number of octets transmitted out of the
interface, including framing characters.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
}
leaf out-unicast-pkts {
type yang:counter64;
description
"The total number of packets that higher-level protocols
requested be transmitted, and that were not addressed
to a multicast or broadcast address at this sub-layer,
including those that were discarded or not sent.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
}
leaf out-broadcast-pkts {
type yang:counter64;
description
"The total number of packets that higher-level protocols
requested be transmitted, and that were addressed to a
broadcast address at this sub-layer, including those
that were discarded or not sent.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCOutBroadcastPkts";
}
leaf out-multicast-pkts {
type yang:counter64;
description
"The total number of packets that higher-level protocols
requested be transmitted, and that were addressed to a
multicast address at this sub-layer, including those
that were discarded or not sent. For a MAC-layer
protocol, this includes both Group and Functional
addresses.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB -
ifHCOutMulticastPkts";
}
leaf out-discards {
type yang:counter32;
description
"The number of outbound packets that were chosen to be
discarded even though no errors had been detected to
prevent their being transmitted. One possible reason
for discarding such a packet could be to free up buffer
space.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifOutDiscards";
}
leaf out-errors {
type yang:counter32;
description
"For packet-oriented interfaces, the number of outbound
packets that could not be transmitted because of errors.
For character-oriented or fixed-length interfaces, the
number of outbound transmission units that could not be
transmitted because of errors.
Discontinuities in the value of this counter can occur
at re-initialization of the management system, and at
other times as indicated by the value of
'discontinuity-time'.";
reference
"RFC 2863: The Interfaces Group MIB - ifOutErrors";
}
}
}
}
}

View File

@@ -0,0 +1,480 @@
module ietf-yang-types {
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
prefix "yang";
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: David Kessens
<mailto:david.kessens@nsn.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>";
description
"This module contains a collection of generally useful derived
YANG data types.
Copyright (c) 2013 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6991; see
the RFC itself for full legal notices.";
revision 2013-07-15 {
description
"This revision adds the following new data types:
- yang-identifier
- hex-string
- uuid
- dotted-quad";
reference
"RFC 6991: Common YANG Data Types";
}
revision 2010-09-24 {
description
"Initial revision.";
reference
"RFC 6021: Common YANG Data Types";
}
/*** collection of counter and gauge types ***/
typedef counter32 {
type uint32;
description
"The counter32 type represents a non-negative integer
that monotonically increases until it reaches a
maximum value of 2^32-1 (4294967295 decimal), when it
wraps around and starts increasing again from zero.
Counters have no defined 'initial' value, and thus, a
single value of a counter has (in general) no information
content. Discontinuities in the monotonically increasing
value normally occur at re-initialization of the
management system, and at other times as specified in the
description of a schema node using this type. If such
other times can occur, for example, the creation of
a schema node of type counter32 at times other than
re-initialization, then a corresponding schema node
should be defined, with an appropriate type, to indicate
the last discontinuity.
The counter32 type should not be used for configuration
schema nodes. A default statement SHOULD NOT be used in
combination with the type counter32.
In the value set and its semantics, this type is equivalent
to the Counter32 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef zero-based-counter32 {
type yang:counter32;
default "0";
description
"The zero-based-counter32 type represents a counter32
that has the defined 'initial' value zero.
A schema node of this type will be set to zero (0) on creation
and will thereafter increase monotonically until it reaches
a maximum value of 2^32-1 (4294967295 decimal), when it
wraps around and starts increasing again from zero.
Provided that an application discovers a new schema node
of this type within the minimum time to wrap, it can use the
'initial' value as a delta. It is important for a management
station to be aware of this minimum time and the actual time
between polls, and to discard data if the actual time is too
long or there is no defined minimum time.
In the value set and its semantics, this type is equivalent
to the ZeroBasedCounter32 textual convention of the SMIv2.";
reference
"RFC 4502: Remote Network Monitoring Management Information
Base Version 2";
}
typedef counter64 {
type uint64;
description
"The counter64 type represents a non-negative integer
that monotonically increases until it reaches a
maximum value of 2^64-1 (18446744073709551615 decimal),
when it wraps around and starts increasing again from zero.
Counters have no defined 'initial' value, and thus, a
single value of a counter has (in general) no information
content. Discontinuities in the monotonically increasing
value normally occur at re-initialization of the
management system, and at other times as specified in the
description of a schema node using this type. If such
other times can occur, for example, the creation of
a schema node of type counter64 at times other than
re-initialization, then a corresponding schema node
should be defined, with an appropriate type, to indicate
the last discontinuity.
The counter64 type should not be used for configuration
schema nodes. A default statement SHOULD NOT be used in
combination with the type counter64.
In the value set and its semantics, this type is equivalent
to the Counter64 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef zero-based-counter64 {
type yang:counter64;
default "0";
description
"The zero-based-counter64 type represents a counter64 that
has the defined 'initial' value zero.
A schema node of this type will be set to zero (0) on creation
and will thereafter increase monotonically until it reaches
a maximum value of 2^64-1 (18446744073709551615 decimal),
when it wraps around and starts increasing again from zero.
Provided that an application discovers a new schema node
of this type within the minimum time to wrap, it can use the
'initial' value as a delta. It is important for a management
station to be aware of this minimum time and the actual time
between polls, and to discard data if the actual time is too
long or there is no defined minimum time.
In the value set and its semantics, this type is equivalent
to the ZeroBasedCounter64 textual convention of the SMIv2.";
reference
"RFC 2856: Textual Conventions for Additional High Capacity
Data Types";
}
typedef gauge32 {
type uint32;
description
"The gauge32 type represents a non-negative integer, which
may increase or decrease, but shall never exceed a maximum
value, nor fall below a minimum value. The maximum value
cannot be greater than 2^32-1 (4294967295 decimal), and
the minimum value cannot be smaller than 0. The value of
a gauge32 has its maximum value whenever the information
being modeled is greater than or equal to its maximum
value, and has its minimum value whenever the information
being modeled is smaller than or equal to its minimum value.
If the information being modeled subsequently decreases
below (increases above) the maximum (minimum) value, the
gauge32 also decreases (increases).
In the value set and its semantics, this type is equivalent
to the Gauge32 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef gauge64 {
type uint64;
description
"The gauge64 type represents a non-negative integer, which
may increase or decrease, but shall never exceed a maximum
value, nor fall below a minimum value. The maximum value
cannot be greater than 2^64-1 (18446744073709551615), and
the minimum value cannot be smaller than 0. The value of
a gauge64 has its maximum value whenever the information
being modeled is greater than or equal to its maximum
value, and has its minimum value whenever the information
being modeled is smaller than or equal to its minimum value.
If the information being modeled subsequently decreases
below (increases above) the maximum (minimum) value, the
gauge64 also decreases (increases).
In the value set and its semantics, this type is equivalent
to the CounterBasedGauge64 SMIv2 textual convention defined
in RFC 2856";
reference
"RFC 2856: Textual Conventions for Additional High Capacity
Data Types";
}
/*** collection of identifier-related types ***/
typedef object-identifier {
type string {
pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ '(\.(0|([1-9]\d*)))*';
}
description
"The object-identifier type represents administratively
assigned names in a registration-hierarchical-name tree.
Values of this type are denoted as a sequence of numerical
non-negative sub-identifier values. Each sub-identifier
value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
are separated by single dots and without any intermediate
whitespace.
The ASN.1 standard restricts the value space of the first
sub-identifier to 0, 1, or 2. Furthermore, the value space
of the second sub-identifier is restricted to the range
0 to 39 if the first sub-identifier is 0 or 1. Finally,
the ASN.1 standard requires that an object identifier
has always at least two sub-identifiers. The pattern
captures these restrictions.
Although the number of sub-identifiers is not limited,
module designers should realize that there may be
implementations that stick with the SMIv2 limit of 128
sub-identifiers.
This type is a superset of the SMIv2 OBJECT IDENTIFIER type
since it is not restricted to 128 sub-identifiers. Hence,
this type SHOULD NOT be used to represent the SMIv2 OBJECT
IDENTIFIER type; the object-identifier-128 type SHOULD be
used instead.";
reference
"ISO9834-1: Information technology -- Open Systems
Interconnection -- Procedures for the operation of OSI
Registration Authorities: General procedures and top
arcs of the ASN.1 Object Identifier tree";
}
typedef object-identifier-128 {
type object-identifier {
pattern '\d*(\.\d*){1,127}';
}
description
"This type represents object-identifiers restricted to 128
sub-identifiers.
In the value set and its semantics, this type is equivalent
to the OBJECT IDENTIFIER type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef yang-identifier {
type string {
length "1..max";
pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
}
description
"A YANG identifier string as defined by the 'identifier'
rule in Section 12 of RFC 6020. An identifier must
start with an alphabetic character or an underscore
followed by an arbitrary sequence of alphabetic or
numeric characters, underscores, hyphens, or dots.
A YANG identifier MUST NOT start with any possible
combination of the lowercase or uppercase character
sequence 'xml'.";
reference
"RFC 6020: YANG - A Data Modeling Language for the Network
Configuration Protocol (NETCONF)";
}
/*** collection of types related to date and time***/
typedef date-and-time {
type string {
pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ '(Z|[\+\-]\d{2}:\d{2})';
}
description
"The date-and-time type is a profile of the ISO 8601
standard for representation of dates and times using the
Gregorian calendar. The profile is defined by the
date-time production in Section 5.6 of RFC 3339.
The date-and-time type is compatible with the dateTime XML
schema type with the following notable exceptions:
(a) The date-and-time type does not allow negative years.
(b) The date-and-time time-offset -00:00 indicates an unknown
time zone (see RFC 3339) while -00:00 and +00:00 and Z
all represent the same time zone in dateTime.
(c) The canonical format (see below) of data-and-time values
differs from the canonical format used by the dateTime XML
schema type, which requires all times to be in UTC using
the time-offset 'Z'.
This type is not equivalent to the DateAndTime textual
convention of the SMIv2 since RFC 3339 uses a different
separator between full-date and full-time and provides
higher resolution of time-secfrac.
The canonical format for date-and-time values with a known time
zone uses a numeric time zone offset that is calculated using
the device's configured known offset to UTC time. A change of
the device's offset to UTC time will cause date-and-time values
to change accordingly. Such changes might happen periodically
in case a server follows automatically daylight saving time
(DST) time zone offset changes. The canonical format for
date-and-time values with an unknown time zone (usually
referring to the notion of local time) uses the time-offset
-00:00.";
reference
"RFC 3339: Date and Time on the Internet: Timestamps
RFC 2579: Textual Conventions for SMIv2
XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
}
typedef timeticks {
type uint32;
description
"The timeticks type represents a non-negative integer that
represents the time, modulo 2^32 (4294967296 decimal), in
hundredths of a second between two epochs. When a schema
node is defined that uses this type, the description of
the schema node identifies both of the reference epochs.
In the value set and its semantics, this type is equivalent
to the TimeTicks type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef timestamp {
type yang:timeticks;
description
"The timestamp type represents the value of an associated
timeticks schema node at which a specific occurrence
happened. The specific occurrence must be defined in the
description of any schema node defined using this type. When
the specific occurrence occurred prior to the last time the
associated timeticks attribute was zero, then the timestamp
value is zero. Note that this requires all timestamp values
to be reset to zero when the value of the associated timeticks
attribute reaches 497+ days and wraps around to zero.
The associated timeticks schema node must be specified
in the description of any schema node using this type.
In the value set and its semantics, this type is equivalent
to the TimeStamp textual convention of the SMIv2.";
reference
"RFC 2579: Textual Conventions for SMIv2";
}
/*** collection of generic address types ***/
typedef phys-address {
type string {
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
}
description
"Represents media- or physical-level addresses represented
as a sequence octets, each octet represented by two hexadecimal
numbers. Octets are separated by colons. The canonical
representation uses lowercase characters.
In the value set and its semantics, this type is equivalent
to the PhysAddress textual convention of the SMIv2.";
reference
"RFC 2579: Textual Conventions for SMIv2";
}
typedef mac-address {
type string {
pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
}
description
"The mac-address type represents an IEEE 802 MAC address.
The canonical representation uses lowercase characters.
In the value set and its semantics, this type is equivalent
to the MacAddress textual convention of the SMIv2.";
reference
"IEEE 802: IEEE Standard for Local and Metropolitan Area
Networks: Overview and Architecture
RFC 2579: Textual Conventions for SMIv2";
}
/*** collection of XML-specific types ***/
typedef xpath1.0 {
type string;
description
"This type represents an XPATH 1.0 expression.
When a schema node is defined that uses this type, the
description of the schema node MUST specify the XPath
context in which the XPath expression is evaluated.";
reference
"XPATH: XML Path Language (XPath) Version 1.0";
}
/*** collection of string types ***/
typedef hex-string {
type string {
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
}
description
"A hexadecimal string with octets represented as hex digits
separated by colons. The canonical representation uses
lowercase characters.";
}
typedef uuid {
type string {
pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
+ '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
}
description
"A Universally Unique IDentifier in the string representation
defined in RFC 4122. The canonical representation uses
lowercase characters.
The following is an example of a UUID in string representation:
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
";
reference
"RFC 4122: A Universally Unique IDentifier (UUID) URN
Namespace";
}
typedef dotted-quad {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
}
description
"An unsigned 32-bit number expressed in the dotted-quad
notation, i.e., four octets written as decimal numbers
and separated with the '.' (full stop) character.";
}
}

View File

@@ -0,0 +1,935 @@
module openconfig-acl {
yang-version "1";
// namespace
namespace "http://openconfig.net/yang/acl";
prefix "oc-acl";
import openconfig-packet-match { prefix oc-match; }
import openconfig-interfaces { prefix oc-if; }
import openconfig-yang-types { prefix oc-yang; }
import openconfig-extensions { prefix oc-ext; }
// meta
organization "OpenConfig working group";
contact
"OpenConfig working group
www.openconfig.net";
description
"This module defines configuration and operational state
data for network access control lists (i.e., filters, rules,
etc.). ACLs are organized into ACL sets, with each set
containing one or more ACL entries. ACL sets are identified
by a unique name, while each entry within a set is assigned
a sequence-id that determines the order in which the ACL
rules are applied to a packet. Note that ACLs are evaluated
in ascending order based on the sequence-id (low to high).
Individual ACL rules specify match criteria based on fields in
the packet, along with an action that defines how matching
packets should be handled. Entries have a type that indicates
the type of match criteria, e.g., MAC layer, IPv4, IPv6, etc.";
oc-ext:openconfig-version "1.3.3";
revision "2023-02-06" {
description
"Add clarifying comments on use of interface-ref.";
reference "1.3.3";
}
revision "2023-01-29" {
description
"Update sequence-id reference to allow model to be re-used
outside of ACL context.";
reference "1.3.2";
}
revision "2022-12-20" {
description
"Remove unused openconfig-inet-types import";
reference "1.3.1";
}
revision "2022-06-01" {
description
"Add the management of prefix lists
that can be used in matches";
reference "1.3.0";
}
revision "2022-01-14" {
description
"Fix when statements for MIXED mode ACLs";
reference "1.2.2";
}
revision "2021-06-16" {
description
"Remove trailing whitespace";
reference "1.2.1";
}
revision "2021-03-17" {
description
"Add MPLS filter Support.";
reference "1.2.0";
}
revision "2019-11-27" {
description
"Fix xpaths in when statements.";
reference "1.1.1";
}
revision "2019-10-25" {
description
"Update when statements.";
reference "1.1.0";
}
revision "2018-11-21" {
description
"Add OpenConfig module metadata extensions.";
reference "1.0.2";
}
revision "2018-04-24" {
description
"Clarified order of ACL evaluation";
reference "1.0.1";
}
revision "2017-05-26" {
description
"Separated ACL entries by type";
reference "1.0.0";
}
revision "2016-08-08" {
description
"OpenConfig public release";
reference "0.2.0";
}
revision "2016-01-22" {
description
"Initial revision";
reference "TBD";
}
// OpenConfig specific extensions for module metadata.
oc-ext:regexp-posix;
oc-ext:catalog-organization "openconfig";
oc-ext:origin "openconfig";
identity ACL_TYPE {
description
"Base identity for types of ACL sets";
}
identity ACL_IPV4 {
base ACL_TYPE;
description
"IP-layer ACLs with IPv4 addresses";
}
identity ACL_IPV6 {
base ACL_TYPE;
description
"IP-layer ACLs with IPv6 addresses";
}
identity ACL_L2 {
base ACL_TYPE;
description
"MAC-layer ACLs";
}
identity ACL_MIXED {
base ACL_TYPE;
description
"Mixed-mode ACL that specifies L2 and L3 protocol
fields. This ACL type is not implemented by many
routing/switching devices.";
}
identity ACL_MPLS {
base ACL_TYPE;
description
"An ACL that matches on fields from the MPLS header.";
}
// ACL action type
identity FORWARDING_ACTION {
description
"Base identity for actions in the forwarding category";
}
identity ACCEPT {
base FORWARDING_ACTION;
description
"Accept the packet";
}
identity DROP {
base FORWARDING_ACTION;
description
"Drop packet without sending any ICMP error message";
}
identity REJECT {
base FORWARDING_ACTION;
description
"Drop the packet and send an ICMP error message to the source";
}
identity LOG_ACTION {
description
"Base identity for defining the destination for logging
actions";
}
identity LOG_SYSLOG {
base LOG_ACTION;
description
"Log the packet in Syslog";
}
identity LOG_NONE {
base LOG_ACTION;
description
"No logging";
}
identity ACL_COUNTER_CAPABILITY {
description
"Base identity for system to indicate how it is able to report
counters";
}
identity INTERFACE_ONLY {
base ACL_COUNTER_CAPABILITY;
description
"ACL counters are available and reported only per interface";
}
identity AGGREGATE_ONLY {
base ACL_COUNTER_CAPABILITY;
description
"ACL counters are aggregated over all interfaces, and reported
only per ACL entry";
}
identity INTERFACE_AGGREGATE {
base ACL_COUNTER_CAPABILITY;
description
"ACL counters are reported per interface, and also aggregated
and reported per ACL entry.";
}
// grouping statements
// input interface
grouping input-interface-config {
description
"Config of interface";
}
grouping input-interface-state {
description
"State information of interface";
}
grouping input-interface-top {
description
"Input interface top level container";
container input-interface {
description
"Input interface container. The interface is resolved based
on the interface and subinterface leaves of the interface-ref
container, which are references to entries in the /interfaces
list.";
container config {
description
"Config data";
uses input-interface-config;
}
container state {
config false;
description
"State information";
uses input-interface-config;
uses input-interface-state;
}
uses oc-if:interface-ref;
}
}
// Action Type
grouping action-config {
description
"Config of action type";
leaf forwarding-action {
type identityref {
base FORWARDING_ACTION;
}
mandatory true;
description
"Specifies the forwarding action. One forwarding action
must be specified for each ACL entry";
}
leaf log-action {
type identityref {
base LOG_ACTION;
}
default LOG_NONE;
description
"Specifies the log action and destination for
matched packets. The default is not to log the
packet.";
}
}
grouping action-state {
description
"State information of action type";
}
grouping action-top {
description
"ACL action type top level container";
container actions {
description
"Enclosing container for list of ACL actions associated
with an entry";
container config {
description
"Config data for ACL actions";
uses action-config;
}
container state {
config false;
description
"State information for ACL actions";
uses action-config;
uses action-state;
}
}
}
grouping acl-counters-state {
description
"Common grouping for ACL counters";
leaf matched-packets {
type oc-yang:counter64;
description
"Count of the number of packets matching the current ACL
entry.
An implementation should provide this counter on a
per-interface per-ACL-entry if possible.
If an implementation only supports ACL counters per entry
(i.e., not broken out per interface), then the value
should be equal to the aggregate count across all interfaces.
An implementation that provides counters per entry per
interface is not required to also provide an aggregate count,
e.g., per entry -- the user is expected to be able implement
the required aggregation if such a count is needed.";
}
leaf matched-octets {
type oc-yang:counter64;
description
"Count of the number of octets (bytes) matching the current
ACL entry.
An implementation should provide this counter on a
per-interface per-ACL-entry if possible.
If an implementation only supports ACL counters per entry
(i.e., not broken out per interface), then the value
should be equal to the aggregate count across all interfaces.
An implementation that provides counters per entry per
interface is not required to also provide an aggregate count,
e.g., per entry -- the user is expected to be able implement
the required aggregation if such a count is needed.";
}
}
// Access List Entries
grouping access-list-entries-config {
description
"Access List Entries (ACE) config.";
leaf sequence-id {
type uint32;
description
"The sequence id determines the order in which ACL entries
are applied. The sequence id must be unique for each entry
in an ACL set. Target devices should apply the ACL entry
rules in ascending order determined by sequence id (low to
high), rather than the relying only on order in the list.";
}
leaf description {
type string;
description
"A user-defined description, or comment, for this Access List
Entry.";
}
}
grouping access-list-entries-state {
description
"Access List Entries state.";
uses acl-counters-state;
}
grouping access-list-entries-top {
description
"Access list entries to level container";
container acl-entries {
description
"Access list entries container";
list acl-entry {
key "sequence-id";
description
"List of ACL entries comprising an ACL set";
leaf sequence-id {
type leafref {
path "../config/sequence-id";
}
description
"references the list key";
}
container config {
description
"Access list entries config";
uses access-list-entries-config;
}
container state {
config false;
description
"State information for ACL entries";
uses access-list-entries-config;
uses access-list-entries-state;
}
uses oc-match:ethernet-header-top {
when "../../config/type='ACL_L2' or " +
"../../config/type='ACL_MIXED'" {
description
"MAC-layer fields are valid when the ACL type is L2 or
MIXED";
}
}
uses oc-match:ipv4-protocol-fields-top {
when "../../config/type='ACL_IPV4' or " +
"../../config/type='ACL_MIXED'" {
description
"IPv4-layer fields are valid when the ACL type is
IPv4 or MIXED";
}
}
uses oc-match:mpls-header-top {
when "../../config/type='ACL_MPLS' or " +
"../../config/type='ACL_MIXED'" {
description
"MPLS-layer fields are valid when the ACL type is
MPLS or MIXED";
}
}
uses oc-match:ipv6-protocol-fields-top {
when "../../config/type='ACL_IPV6' or " +
"../../config/type='ACL_MIXED'" {
description
"IPv6-layer fields are valid when the ACL type is
IPv6 or MIXED";
}
}
uses oc-match:transport-fields-top {
when "../../config/type='ACL_IPV6' or " +
"../../config/type='ACL_IPV4' or " +
"../../config/type='ACL_MIXED'" {
description
"Transport-layer fields are valid when specifying
L3 or MIXED ACL types";
}
}
uses input-interface-top;
uses action-top;
}
}
}
grouping acl-set-config {
description
"Access Control List config";
leaf name {
type string;
description
"The name of the access-list set";
}
leaf type {
type identityref {
base ACL_TYPE;
}
description
"The type determines the fields allowed in the ACL entries
belonging to the ACL set (e.g., IPv4, IPv6, etc.)";
}
leaf description {
type string;
description
"Description, or comment, for the ACL set";
}
}
grouping acl-set-state {
description
"Access Control List state";
}
grouping acl-set-top {
description
"Access list entries variables top level container";
container acl-sets {
description
"Access list entries variables enclosing container";
list acl-set {
key "name type";
description
"List of ACL sets, each comprising of a list of ACL
entries";
leaf name {
type leafref {
path "../config/name";
}
description
"Reference to the name list key";
}
leaf type {
type leafref {
path "../config/type";
}
description
"Reference to the type list key";
}
container config {
description
"Access list config";
uses acl-set-config;
}
container state {
config false;
description
"Access list state information";
uses acl-set-config;
uses acl-set-state;
}
uses access-list-entries-top;
}
}
}
grouping interface-acl-entries-config {
description
"Configuration data for per-interface ACLs";
}
grouping interface-acl-entries-state {
description
"Operational state data for per-interface ACL entries";
leaf sequence-id {
type leafref {
path "/oc-acl:acl/oc-acl:acl-sets/" +
"oc-acl:acl-set[oc-acl:name=current()/../../../../set-name]" +
"[oc-acl:type=current()/../../../../type]/" +
"oc-acl:acl-entries/oc-acl:acl-entry/oc-acl:sequence-id";
}
description
"Reference to an entry in the ACL set applied to an
interface";
}
uses acl-counters-state;
}
grouping interface-acl-entries-top {
description
"Top-level grouping for per-interface ACL entries";
container acl-entries {
config false;
description
"Enclosing container for list of references to ACLs";
list acl-entry {
key "sequence-id";
description
"List of ACL entries assigned to an interface";
leaf sequence-id {
type leafref {
path "../state/sequence-id";
}
description
"Reference to per-interface acl entry key";
}
// no config container since the enclosing container is
// read-only
container state {
config false;
description
"Operational state data for per-interface ACL entries";
uses interface-acl-entries-config;
uses interface-acl-entries-state;
}
}
}
}
grouping interface-ingress-acl-config {
description
"Configuration data for per-interface ingress ACLs";
leaf set-name {
type leafref {
path "../../../../../../acl-sets/acl-set/config/name";
}
description
"Reference to the ACL set name applied on ingress";
}
leaf type {
type leafref {
path "../../../../../../acl-sets/acl-set[name=current()/../set-name]" +
"/config/type";
}
description
"Reference to the ACL set type applied on ingress";
}
}
grouping interface-ingress-acl-state {
description
"Operational state data for the per-interface ingress ACL";
}
grouping interface-ingress-acl-top {
description
"Top-level grouping for per-interface ingress ACL data";
container ingress-acl-sets {
description
"Enclosing container the list of ingress ACLs on the
interface";
list ingress-acl-set {
key "set-name type";
description
"List of ingress ACLs on the interface";
leaf set-name {
type leafref {
path "../config/set-name";
}
description
"Reference to set name list key";
}
leaf type {
type leafref {
path "../config/type";
}
description
"Reference to type list key";
}
container config {
description
"Configuration data ";
uses interface-ingress-acl-config;
}
container state {
config false;
description
"Operational state data for interface ingress ACLs";
uses interface-ingress-acl-config;
uses interface-ingress-acl-state;
}
uses interface-acl-entries-top;
}
}
}
grouping interface-egress-acl-config {
description
"Configuration data for per-interface egress ACLs";
leaf set-name {
type leafref {
path "../../../../../../acl-sets/acl-set/config/name";
}
description
"Reference to the ACL set name applied on egress";
}
leaf type {
type leafref {
path "../../../../../../acl-sets/acl-set[name=current()/../set-name]" +
"/config/type";
}
description
"Reference to the ACL set type applied on egress.";
}
}
grouping interface-egress-acl-state {
description
"Operational state data for the per-interface egress ACL";
}
grouping interface-egress-acl-top {
description
"Top-level grouping for per-interface egress ACL data";
container egress-acl-sets {
description
"Enclosing container the list of egress ACLs on the
interface";
list egress-acl-set {
key "set-name type";
description
"List of egress ACLs on the interface";
leaf set-name {
type leafref {
path "../config/set-name";
}
description
"Reference to set name list key";
}
leaf type {
type leafref {
path "../config/type";
}
description
"Reference to type list key";
}
container config {
description
"Configuration data ";
uses interface-egress-acl-config;
}
container state {
config false;
description
"Operational state data for interface egress ACLs";
uses interface-egress-acl-config;
uses interface-egress-acl-state;
}
uses interface-acl-entries-top;
}
}
}
grouping acl-interfaces-config {
description
"Configuration data for interface references";
leaf id {
type oc-if:interface-id;
description
"User-defined identifier for the interface -- a common
convention could be '<if name>.<subif index>'";
}
}
grouping acl-interfaces-state {
description
"Operational state data for interface references";
}
grouping acl-interfaces-top {
description
"Top-level grouping for interface-specific ACL data";
container interfaces {
description
"Enclosing container for the list of interfaces on which
ACLs are set";
list interface {
key "id";
description
"List of interfaces on which ACLs are set. The interface is resolved
based on the interface and subinterface leaves of the interface-ref
container, which are references to entries in the /interfaces
list. The key of the list is an arbitrary value that the
implementation should not use to resolve an interface name.";
leaf id {
type leafref {
path "../config/id";
}
description
"Reference to the interface id list key";
}
container config {
description
"Configuration for ACL per-interface data";
uses acl-interfaces-config;
}
container state {
config false;
description
"Operational state for ACL per-interface data";
uses acl-interfaces-config;
uses acl-interfaces-state;
}
uses oc-if:interface-ref;
uses interface-ingress-acl-top;
uses interface-egress-acl-top;
}
}
}
grouping acl-config {
description
"Global configuration data for ACLs";
}
grouping acl-state {
description
"Global operational state data for ACLs";
leaf counter-capability {
type identityref {
base ACL_COUNTER_CAPABILITY;
}
description
"System reported indication of how ACL counters are reported
by the target";
}
}
grouping acl-top {
description
"Top level grouping for ACL data and structure";
container acl {
description
"Top level enclosing container for ACL model config
and operational state data";
container config {
description
"Global config data for ACLs";
uses acl-config;
}
container state {
config false;
description
"Global operational state data for ACLs";
uses acl-config;
uses acl-state;
}
uses acl-set-top;
uses acl-interfaces-top;
}
}
// data definition statements
uses acl-top;
// augment statements
}

View File

@@ -0,0 +1,227 @@
module openconfig-defined-sets {
yang-version "1";
// namespace
namespace "http://openconfig.net/yang/defined-sets";
prefix "oc-sets";
import openconfig-extensions { prefix oc-ext; }
import openconfig-inet-types { prefix oc-inet; }
import openconfig-packet-match-types { prefix oc-pkt-match-types; }
// meta
organization "OpenConfig working group";
contact
"OpenConfig working group
www.openconfig.net";
description
"This module defines configuration and operational state
data for defined sets (sets of IPv4 prefixes, sets of
IPv6 prefixes, sets of ports, etc). These sets are used,
for example, in network access control lists (i.e., filters,
rules, etc.) in the matching fields.";
oc-ext:openconfig-version "1.0.0";
revision "2022-12-14" {
description
"Initial version of the defined set model";
reference "1.0.0";
}
// OpenConfig specific extensions for module metadata.
oc-ext:catalog-organization "openconfig";
oc-ext:origin "openconfig";
grouping ipv4-prefix-sets-config {
description "Configuration parameters of IPv4 prefix sets.";
leaf name {
type string;
description
"A user defined name of the IPv4 prefix set.";
}
leaf description {
type string;
description "A user defined IPv4 prefix set description.";
}
leaf-list prefix {
type oc-inet:ipv4-prefix;
description
"A user defined list of IPv4 prefixes to be used in match
conditions. Each entry is a IPv4 + mask combination.";
}
}
grouping ipv6-prefix-sets-config {
description "Configuration parameters of IPv6 prefix sets.";
leaf name {
type string;
description
"Name of the IPv6 prefix set.";
}
leaf description {
type string;
description
"A user defined IPv6 prefix set description.";
}
leaf-list prefix {
type oc-inet:ipv6-prefix;
description
"A user defined list of IPv6 prefixes to be used in match
conditions. Each entry is a IPv6 + mask combination.";
}
}
grouping port-sets-config {
description
"Configuration parameters of port sets.";
leaf name {
type string;
description
"A user defined name of the port set.";
}
leaf description {
type string;
description
"A user defined description for the port set";
}
leaf-list port {
type oc-pkt-match-types:port-num-range;
description
"A user defined set of ports to be
used in the match conditions.";
}
}
grouping defined-sets {
description "Configuration of Defined Sets.";
container ipv4-prefix-sets {
description
"Container to hold the list of IPv4 prefix sets.";
list ipv4-prefix-set {
key "name";
description
"List of IPv4 prefix sets.";
leaf name {
type leafref {
path "../config/name";
}
description
"Reference to the name of the IPv4 prefix set.";
}
container config {
description
"Configuration data for IPv4 prefix sets.";
uses ipv4-prefix-sets-config;
}
container state {
config false;
description
"State data for IPv4 prefix sets.";
uses ipv4-prefix-sets-config;
}
}
}
container ipv6-prefix-sets {
description
"Container to hold the list of IPv4 prefix sets.";
list ipv6-prefix-set {
key "name";
description "List of IPv6 prefix sets. Each defined set
is uniquely identified by a name";
leaf name {
type leafref {
path "../config/name";
}
description
"Reference to the name of the IPv6 prefix set.";
}
container config {
description
"Configuration data for IPv6 prefix sets.";
uses ipv6-prefix-sets-config;
}
container state {
config false;
description
"State data for prefix lists.";
uses ipv6-prefix-sets-config;
}
}
}
container port-sets {
description
"Container to hold the list of port sets.";
list port-set {
key "name";
description
"List of port sets. Each por set is uniquely
identified by its name";
leaf name {
type leafref {
path "../config/name";
}
description
"Name of the port set. The name is used to
reference the set in match conditions.";
}
container config {
description
"Configuration data for port lists.";
uses port-sets-config;
}
container state {
config false;
description
"State data for port lists.";
uses port-sets-config;
}
}
}
}
grouping defined-sets-top {
description
"Top level grouping for defined-sets";
container defined-sets {
description
"Top level enclosing container for defined-set model
config and operational state data.";
uses defined-sets;
}
}
uses defined-sets-top;
}

View File

@@ -0,0 +1,229 @@
module openconfig-extensions {
yang-version "1";
// namespace
namespace "http://openconfig.net/yang/openconfig-ext";
prefix "oc-ext";
// meta
organization "OpenConfig working group";
contact
"OpenConfig working group
www.openconfig.net";
description
"This module provides extensions to the YANG language to allow
OpenConfig specific functionality and meta-data to be defined.";
oc-ext:openconfig-version "0.6.0";
revision "2024-09-19" {
description
"Add telemetry-atomic-exempt annotation.";
reference "0.6.0";
}
revision "2022-10-05" {
description
"Add missing version statement.";
reference "0.5.1";
}
revision "2020-06-16" {
description
"Add extension for POSIX pattern statements.";
reference "0.5.0";
}
revision "2018-10-17" {
description
"Add extension for regular expression type.";
reference "0.4.0";
}
revision "2017-04-11" {
description
"rename password type to 'hashed' and clarify description";
reference "0.3.0";
}
revision "2017-01-29" {
description
"Added extension for annotating encrypted values.";
reference "0.2.0";
}
revision "2015-10-09" {
description
"Initial OpenConfig public release";
reference "0.1.0";
}
// extension statements
extension openconfig-version {
argument "semver" {
yin-element false;
}
description
"The OpenConfig version number for the module. This is
expressed as a semantic version number of the form:
x.y.z
where:
* x corresponds to the major version,
* y corresponds to a minor version,
* z corresponds to a patch version.
This version corresponds to the model file within which it is
defined, and does not cover the whole set of OpenConfig models.
Individual YANG modules are versioned independently -- the
semantic version is generally incremented only when there is a
change in the corresponding file. Submodules should always
have the same semantic version as their parent modules.
A major version number of 0 indicates that this model is still
in development (whether within OpenConfig or with industry
partners), and is potentially subject to change.
Following a release of major version 1, all modules will
increment major revision number where backwards incompatible
changes to the model are made.
The minor version is changed when features are added to the
model that do not impact current clients use of the model.
The patch-level version is incremented when non-feature changes
(such as bugfixes or clarifications to human-readable
descriptions that do not impact model functionality) are made
that maintain backwards compatibility.
The version number is stored in the module meta-data.";
}
extension openconfig-hashed-value {
description
"This extension provides an annotation on schema nodes to
indicate that the corresponding value should be stored and
reported in hashed form.
Hash algorithms are by definition not reversible. Clients
reading the configuration or applied configuration for the node
should expect to receive only the hashed value. Values written
in cleartext will be hashed. This annotation may be used on
nodes such as secure passwords in which the device never reports
a cleartext value, even if the input is provided as cleartext.";
}
extension regexp-posix {
description
"This extension indicates that the regular expressions included
within the YANG module specified are conformant with the POSIX
regular expression format rather than the W3C standard that is
specified by RFC6020 and RFC7950.";
}
extension posix-pattern {
argument "pattern" {
yin-element false;
}
description
"Provides a POSIX ERE regular expression pattern statement as an
alternative to YANG regular expresssions based on XML Schema Datatypes.
It is used the same way as the standard YANG pattern statement defined in
RFC6020 and RFC7950, but takes an argument that is a POSIX ERE regular
expression string.";
reference
"POSIX Extended Regular Expressions (ERE) Specification:
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04";
}
extension telemetry-on-change {
description
"The telemetry-on-change annotation is specified in the context
of a particular subtree (container, or list) or leaf within the
YANG schema. Where specified, it indicates that the value stored
by the nodes within the context change their value only in response
to an event occurring. The event may be local to the target, for
example - a configuration change, or external - such as the failure
of a link.
When a telemetry subscription allows the target to determine whether
to export the value of a leaf in a periodic or event-based fashion
(e.g., TARGET_DEFINED mode in gNMI), leaves marked as
telemetry-on-change should only be exported when they change,
i.e., event-based.";
}
extension telemetry-atomic {
description
"The telemetry-atomic annotation is specified in the context of
a subtree (container, or list), and indicates that all nodes
within the subtree are always updated together within the data
model. For example, all elements under the subtree may be updated
as a result of a new alarm being raised, or the arrival of a new
protocol message.
Transport protocols may use the atomic specification to determine
optimisations for sending or storing the corresponding data.";
}
extension telemetry-atomic-exempt {
description
"The telemetry-atomic-exempt annotation is specified in the context
of a node or subtree (container, or list), and indicates that the node
or all nodes within the subtree are not always updated together within
the data model of the parent tree. All elements under the subtree may
not be updated as a result of a new alarm being raised, or the arrival
of a new protocol message that updates the parent tree.
This annotation allows parent tree containers with telemetry-atomic
annotation to not be updated when a more frequently updated node or
subtree. For example, a counters container is present.
This extension should only be used when there is a parent that
contains telemetry-atomic extension.";
}
extension operational {
description
"The operational annotation is specified in the context of a
grouping, leaf, or leaf-list within a YANG module. It indicates
that the nodes within the context are derived state on the device.
OpenConfig data models divide nodes into the following three categories:
- intended configuration - these are leaves within a container named
'config', and are the writable configuration of a target.
- applied configuration - these are leaves within a container named
'state' and are the currently running value of the intended configuration.
- derived state - these are the values within the 'state' container which
are not part of the applied configuration of the device. Typically, they
represent state values reflecting underlying operational counters, or
protocol statuses.";
}
extension catalog-organization {
argument "org" {
yin-element false;
}
description
"This extension specifies the organization name that should be used within
the module catalogue on the device for the specified YANG module. It stores
a pithy string where the YANG organization statement may contain more
details.";
}
extension origin {
argument "origin" {
yin-element false;
}
description
"This extension specifies the name of the origin that the YANG module
falls within. This allows multiple overlapping schema trees to be used
on a single network element without requiring module based prefixing
of paths.";
}
}

View File

@@ -0,0 +1,540 @@
module openconfig-icmpv4-types {
yang-version "1";
namespace "http://openconfig.net/yang/openconfig-icmpv4-types";
prefix "oc-icmpv4-types";
import openconfig-extensions { prefix oc-ext; }
organization "OpenConfig working group";
contact
"OpenConfig working group
www.openconfig.net";
description
"OpenConfig module defining the types and coresponding codes for
ICMPv4.";
oc-ext:openconfig-version "0.1.0";
revision "2023-01-26" {
description
"Initial revision of ICMPv4 types module.";
reference "0.1.0";
}
identity TYPE {
description
"Base identity for ICMPv4 codes";
}
identity CODE {
description
"Base identity for ICMPv4 codes.";
}
identity ECHO_REPLY {
description
"ICMP echo reply, value 0.";
base TYPE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity DST_UNREACHABLE {
description
"ICMP destination unreachable, value 3.";
base TYPE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity REDIRECT {
description
"ICMP redirect, value 5.";
base TYPE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity ECHO {
description
"ICMP echo, value 8.";
base TYPE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity ROUTER_ADVERTISEMENT {
description
"ICMP router advertisement, value 9.";
base TYPE;
reference "RFC1256: ICMP Router Discovery Messages";
}
identity ROUTER_SOLICITATION {
description
"ICMP Router Solicitation, value 10.";
base TYPE;
reference "RFC1256: ICMP Router Discovery Messages";
}
identity TIME_EXCEEDED {
description
"ICMP TTL exceede, value 11.";
base TYPE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity PARAM_PROBLEM {
description
"ICMP parameter problem, value 12.";
base TYPE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity TIMESTAMP {
description
"ICMP timestamp, value 13.";
base TYPE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity TIMESTAMP_REPLY {
description
"ICMP timestamp reply, value 14.";
base TYPE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity TRACEROUTE{
description
"Traceroute (deprecated), value 30.";
base TYPE;
reference "RFC1393: Traceroute Using an IP Option";
}
identity PHOTURIS {
description
"ICMP Photuris, value 40.";
base TYPE;
reference "RFC2521: CMP Security Failures Messages";
}
identity EXT_ECHO_REQUEST {
description
"ICMP extended echo request, value 42.";
base TYPE;
reference "RFC8335: PROBE: A Utility for Probing Interfaces";
}
identity EXT_ECHO_REPLY {
description
"ICMP extended echo reply, value 43.";
base TYPE;
reference "RFC8335: PROBE: A Utility for Probing Interfaces";
}
identity ECHO_REPLY_CODE {
description
"CODE for ICMPv4 Echo Reply.";
base CODE;
}
identity ECHO_REPLY_NONE {
description
"No code, type 0 for Echo Reply.";
base ECHO_REPLY_CODE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity DST_UNREACHABLE_CODE {
description
"Codes for ICMPv4 Destination Unreachable.";
base CODE;
}
identity DST_UNREACHABLE_NET {
description
"ICMPv4 destination network unreachable, code 0.";
base DST_UNREACHABLE_CODE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity DST_UNREACHABLE_HOST {
description
"ICMPv4 destination host unreachable, code 1";
base DST_UNREACHABLE_CODE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity DST_UNREACHABLE_PROTOCOL {
description
"ICMPv4 destination protocol unreachable, code 2.";
base DST_UNREACHABLE_CODE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity DST_UNREACHABLE_PORT {
description
"ICMPv4 Port unreachable, code 3.";
base DST_UNREACHABLE_CODE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity DST_UNREACHABLE_CANNOT_FRAGMENT {
description
"ICMPv4 destination unreachable due to inability to fragment. The df-bit
is set but the packet requires fragmentation, code 4.";
base DST_UNREACHABLE_CODE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity DST_UNREACHABLE_SRC_ROUTE_FAILED {
description
"ICMPv4 destination is unreachable as source routing failed, code 5.";
base DST_UNREACHABLE_CODE;
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity DST_UNREACHABLE_DST_NET_UNKNOWN {
description
"ICMPv4 destination is unreachable as the destination network is
unknown, code 6.";
base DST_UNREACHABLE_CODE;
reference "RFC1122: Requirements for Internet Hosts --
Communication Layers";
}
identity DST_UNREACHABLE_DST_HOST_UNKNOWN {
description
"ICMPv4 destination is unreachable as the destination host is unknown, code 7.";
base DST_UNREACHABLE_CODE;
reference "RFC1122: Requirements for Internet Hosts --
Communication Layers";
}
identity DST_UNREACHABLE_SRC_HOST_ISOLATED {
description
"ICMPv4 destination unreachable as the source host is isolated, code 8.";
base DST_UNREACHABLE_CODE;
reference "RFC1122: Requirements for Internet Hosts --
Communication Layers";
}
identity DST_UNREACHABLE_DST_NET_ADMIN_PROHIBITED {
description
"ICMPv4 destination is unreachable as communication with the destination
network is administratively prohibited, code 9.";
base DST_UNREACHABLE_CODE;
reference "RFC1122: Requirements for Internet Hosts --
Communication Layers";
}
identity DST_UNREACHABLE_DST_HOST_ADMIN_PROHIBITED {
description
"ICMPv4 destination is unreachable as communication with the destination
host is adminstratively prohibited, code 10.";
base DST_UNREACHABLE_CODE;
reference "RFC1122: Requirements for Internet Hosts --
Communication Layers";
}
identity DST_UNREACHABLE_NET_UNREACHABLE_FOR_TOS {
description
"ICMPv4 destination network is unreachable for the specified type of
service, code 11.";
base DST_UNREACHABLE_CODE;
reference "RFC1122: Requirements for Internet Hosts --
Communication Layers";
}
identity DST_UNREACHABLE_HOST_UNREACHABLE_FOR_TOS {
description
"ICMPv4 destination host is unreachable for the specified type of
service, code 12.";
base DST_UNREACHABLE_CODE;
reference "RFC1122: Requirements for Internet Hosts --
Communication Layers";
}
identity DST_UNREACHABLE_ADMIN_PROHIBITED {
description
"ICMPv4 destination is unreacable as packets were adminstratively
filtered.";
base DST_UNREACHABLE_CODE;
reference "RFC1812: Requirements for IP Version 4 Routers";
}
identity DST_UNREACHABLE_HOST_PRECEDENCE_VIOLATION {
description
"ICMPv4 destination is unreachable as the first-hop router has determined
that the destination cannot be reached for the specified source/
destination host, network, upper-layer protocol and source/destination
port. Code 14";
base DST_UNREACHABLE_CODE;
}
identity DST_UNREACHABLE_PRECEDENCE_CUTOFF {
description
"ICMPv4 Precedence cutoff in effect. The network operators have imposed
a minimum level of precedence required for operation, the
datagram was sent with a precedence below this level.
Code 15.";
base DST_UNREACHABLE_CODE;
reference "RFC1812: Requirements for IP Version 4 Routers";
}
identity REDIRECT_CODE {
base CODE;
description
"Codes for the ICMPv4 Redirect type.";
}
identity REDIRECT_NETWORK {
base REDIRECT_CODE;
description
"ICMP redirect is being issued for the network or subnet,
code 0";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity REDIRECT_HOST {
base REDIRECT_CODE;
description
"ICMP redirect is being issued for the host, code 1.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity REDIRECT_TOS_NETWORK {
base REDIRECT_CODE;
description
"ICMP redirect is being issued for the network and type of service. code 2.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity REDIRECT_TOS_HOST {
base REDIRECT_CODE;
description
"ICMP redirect is being issued for the host and type of service,
code 3";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity ECHO_CODE {
base CODE;
description
"Codes for ICMPv4 echo messages.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity ECHO_NO_CODE {
base ECHO_CODE;
description
"No code.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity ROUTER_ADVERTISEMENT_CODE {
base CODE;
description
"Code for the ICMPv4 router advertisement message.";
}
identity ROUTER_ADVERTISEMENT_NORMAL {
base ROUTER_ADVERTISEMENT_CODE;
description
"Code 0: Normal router advertisement.";
reference "RFC3344: IP Mobility Support for IPv4";
}
identity ROUTER_ADVERTISEMENT_DOES_NOT_ROUTE_COMMON {
base ROUTER_ADVERTISEMENT_CODE;
description
"Code 16: Does not route common traffic.";
reference "RFC3344: IP Mobility Support for IPv4";
}
identity ROUTER_SELECTION_CODE {
base CODE;
description
"Codes for the ICMPv4 router selection message.";
}
identity ROUTER_SELECTION_NO_CODE {
base ROUTER_SELECTION_CODE;
description
"No code.";
reference "RFC1256: ICMP Router Discovery Messages";
}
identity TIME_EXCEEDED_CODE {
base CODE;
description
"Codes for the ICMPv4 time exceeded code.";
}
identity TIME_EXCEEDED_IN_TRANSIT {
base TIME_EXCEEDED_CODE;
description
"Code 0: Time to Live exceeded in Transit.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity TIME_EXCEEDED_FRAGMENT_REASSEMBLY_IN_TRANSIT {
base TIME_EXCEEDED_CODE;
description
"Code 1: Fragment reassembly time exceeded.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity PARAM_PROBLEM_CODE {
base CODE;
description
"Codes for the ICMPv4 parameter problem message (Type 12).";
}
identity PARAM_PROBLEM_POINTER_INDICATES_ERR {
base PARAM_PROBLEM_CODE;
description
"Code 0: Pointer indicates the error.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity PARAM_PROBLEM_MISSING_REQ_OPTION {
base PARAM_PROBLEM_CODE;
description
"Code 1: Missing a required option.";
reference "RFC1108: U.S. Department of Defense
Security Options for the Internet Protocol";
}
identity PARAM_PROBLEM_BAD_LENGTH {
base PARAM_PROBLEM_CODE;
description
"Code 2: Bad Length.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity TIMESTAMP_CODE {
base CODE;
description
"Codes of the ICMPv4 timestamp message (Type 13).";
}
identity TIMESTAMP_NO_CODE {
base TIMESTAMP_CODE;
description
"No code.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity TIMESTAMP_REPLY_CODE {
base CODE;
description
"Codes of the ICMPv4 timestamp reply message (Type 14).";
}
identity TIMESTAMP_REPLY_NO_CODE {
base TIMESTAMP_REPLY_CODE;
description
"No code.";
reference "RFC792: INTERNET CONTROL MESSAGE PROTOCOL";
}
identity PHOTURIS_CODE {
base CODE;
description
"Codes of the ICMPv4 Photuris message (type 40).";
}
identity PHOTURIS_BAD_SPI {
base PHOTURIS_CODE;
description
"Code 0: Bad SPI.";
reference "RFC2521: ICMP Security Failures Messages";
}
identity PHOTURIS_AUTH_FAILED {
base PHOTURIS_CODE;
description
"Code 1: Authentication failed.";
reference "RFC2521: ICMP Security Failures Messages";
}
identity PHOTURIS_DECOMPRESS_FAILED {
base PHOTURIS_CODE;
description
"Code 2: Decompression failed.";
reference "RFC2521: ICMP Security Failures Messages";
}
identity PHOTURIS_DECRYPTION_FAILED {
base PHOTURIS_CODE;
description
"Code 3: Decryption failed.";
reference "RFC2521: ICMP Security Failures Messages";
}
identity PHOTURIS_NEED_AUTHENTICATION {
base PHOTURIS_CODE;
description
"Code 4: Need authentication.";
reference "RFC2521: ICMP Security Failures Messages";
}
identity PHOTURIS_NEED_AUTHORIZATION {
base PHOTURIS_CODE;
description
"Code 5: Need authorization.";
reference "RFC2521: ICMP Security Failures Messages";
}
identity EXT_ECHO_REQUEST_CODE {
description
"Codes of the extended echo request ICMP message.";
base CODE;
}
identity EXT_ECHO_REQUEST_NO_ERROR {
base EXT_ECHO_REQUEST_CODE;
description
"Code 0: No error.";
reference "RFC8335: PROBE: A Utility for Probing Interfaces";
}
identity EXT_ECHO_REPLY_CODE {
description
"Codes of the extended echo reply ICMP message (Type 43).";
base CODE;
}
identity EXT_ECHO_REPLY_NO_ERROR {
base EXT_ECHO_REPLY_CODE;
description
"Code 0: No error.";
reference "RFC8335: PROBE: A Utility for Probing Interfaces";
}
identity EXT_ECHO_REPLY_MALFORMED_QUERY {
base EXT_ECHO_REPLY_CODE;
description
"Code 1: Malformed query.";
reference "RFC8335: PROBE: A Utility for Probing Interfaces";
}
identity EXT_ECHO_REPLY_NO_SUCH_INTF {
base EXT_ECHO_REPLY_CODE;
description
"Code 2: No such interface.";
reference "RFC8335: PROBE: A Utility for Probing Interfaces";
}
identity EXT_ECHO_REPLY_NO_SUB_TABLE_ENTRY {
base EXT_ECHO_REPLY_CODE;
description
"Code 3: No such table entry.";
reference "RFC8335: PROBE: A Utility for Probing Interfaces";
}
identity EXT_ECHO_REPLY_MULTIPLE_INTF_SATISFY_QUERY {
base EXT_ECHO_REPLY_CODE;
description
"Code 4: Multiple interfaces satisfy query.";
reference "RFC8335: PROBE: A Utility for Probing Interfaces";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,485 @@
module openconfig-inet-types {
yang-version "1";
namespace "http://openconfig.net/yang/types/inet";
prefix "oc-inet";
import openconfig-extensions { prefix "oc-ext"; }
organization
"OpenConfig working group";
contact
"OpenConfig working group
www.openconfig.net";
description
"This module contains a set of Internet address related
types for use in OpenConfig modules.
Portions of this code were derived from IETF RFC 6021.
Please reproduce this note if possible.
IETF code is subject to the following copyright and license:
Copyright (c) IETF Trust and the persons identified as authors of
the code.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, is permitted pursuant to, and subject to the license
terms contained in, the Simplified BSD License set forth in
Section 4.c of the IETF Trust's Legal Provisions Relating
to IETF Documents (http://trustee.ietf.org/license-info).";
oc-ext:openconfig-version "0.7.0";
revision "2024-01-05" {
description
"Change ipv6-address-zoned typedef to conform to W3C standard
regex pattern.";
reference "0.7.0";
}
revision "2023-02-06" {
description
"Add ipv6-link-local and ipv6-address-type";
reference "0.6.0";
}
revision "2021-08-17" {
description
"Add ip-address-zoned typedef as a union between ipv4-address-zoned
and ipv6-address-zoned types.";
reference "0.5.0";
}
revision "2021-07-14" {
description
"Use auto-generated regex for ipv4 pattern statements:
- ipv4-address
- ipv4-address-zoned
- ipv4-prefix";
reference "0.4.1";
}
revision "2021-01-07" {
description
"Remove module extension oc-ext:regexp-posix by making pattern regexes
conform to RFC7950.
Types impacted:
- ipv4-address
- ipv4-address-zoned
- ipv6-address
- domain-name";
reference "0.4.0";
}
revision "2020-10-12" {
description
"Fix anchors for domain-name pattern.";
reference "0.3.5";
}
revision "2020-06-30" {
description
"Add OpenConfig POSIX pattern extensions and add anchors for domain-name
pattern.";
reference "0.3.4";
}
revision "2019-04-25" {
description
"Fix regex bug for ipv6-prefix type";
reference "0.3.3";
}
revision "2018-11-21" {
description
"Add OpenConfig module metadata extensions.";
reference "0.3.2";
}
revision 2017-08-24 {
description
"Minor formatting fixes.";
reference "0.3.1";
}
revision 2017-07-06 {
description
"Add domain-name and host typedefs";
reference "0.3.0";
}
revision 2017-04-03 {
description
"Add ip-version typedef.";
reference "0.2.0";
}
revision 2017-04-03 {
description
"Update copyright notice.";
reference "0.1.1";
}
revision 2017-01-26 {
description
"Initial module for inet types";
reference "0.1.0";
}
// OpenConfig specific extensions for module metadata.
oc-ext:catalog-organization "openconfig";
oc-ext:origin "openconfig";
// IPv4 and IPv6 types.
typedef ipv4-address {
type string {
pattern
'([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]|'
+ '[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}';
oc-ext:posix-pattern
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]|'
+ '[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3})$';
}
description
"An IPv4 address in dotted quad notation using the default
zone.";
}
typedef ipv4-address-zoned {
type string {
pattern
'([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]|'
+ '[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}(%[a-zA-Z0-9_]+)';
oc-ext:posix-pattern
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]|'
+ '[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}(%[a-zA-Z0-9_]+))$';
}
description
"An IPv4 address in dotted quad notation. This type allows
specification of a zone index to disambiguate identical
address values. For link-local addresses, the index is
typically the interface index or interface name.";
}
typedef ipv6-address {
type string {
pattern
// Must support compression through different lengths
// therefore this regexp is complex.
'(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,7}:|' +
'([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|' +
'([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|' +
'([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|' +
'([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|' +
'[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|' +
':((:[0-9a-fA-F]{1,4}){1,7}|:)' +
')';
oc-ext:posix-pattern
// Must support compression through different lengths
// therefore this regexp is complex.
'^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,7}:|' +
'([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|' +
'([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|' +
'([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|' +
'([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|' +
'[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|' +
':((:[0-9a-fA-F]{1,4}){1,7}|:)' +
')$';
}
description
"An IPv6 address represented as either a full address; shortened
or mixed-shortened formats, using the default zone.";
}
typedef ipv6-address-zoned {
type string {
pattern
// Must support compression through different lengths
// therefore this regexp is complex.
'(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,7}:|' +
'([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|' +
'([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|' +
'([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|' +
'([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|' +
'[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|' +
':((:[0-9a-fA-F]{1,4}){1,7}|:)' +
')(%[a-zA-Z0-9_]+)';
oc-ext:posix-pattern
// Must support compression through different lengths
// therefore this regexp is complex.
'^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,7}:|' +
'([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|' +
'([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|' +
'([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|' +
'([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|' +
'[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|' +
':((:[0-9a-fA-F]{1,4}){1,7}|:)' +
')(%[a-zA-Z0-9_]+)$';
}
description
"An IPv6 address represented as either a full address; shortened
or mixed-shortened formats. This type allows specification of
a zone index to disambiguate identical address values. For
link-local addresses, the index is typically the interface
index or interface name.";
}
typedef ipv4-prefix {
type string {
pattern
'([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]|'
+ '[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}/([0-9]|[12][0-9]|'
+ '3[0-2])';
oc-ext:posix-pattern
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]|'
+ '[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}/([0-9]|[12][0-9]|'
+ '3[0-2]))$';
}
description
"An IPv4 prefix represented in dotted quad notation followed by
a slash and a CIDR mask (0 <= mask <= 32).";
}
typedef ipv6-prefix {
type string {
pattern
'(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,7}:|' +
'([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|' +
'([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|' +
'([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|' +
'([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|' +
'[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|' +
':((:[0-9a-fA-F]{1,4}){1,7}|:)' +
')/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9])';
oc-ext:posix-pattern
'^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,7}:|' +
'([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|' +
'([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|' +
'([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|' +
'([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|' +
'([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|' +
'[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|' +
':((:[0-9a-fA-F]{1,4}){1,7}|:)' +
')/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9])$';
}
description
"An IPv6 prefix represented in full, shortened, or mixed
shortened format followed by a slash and CIDR mask
(0 <= mask <= 128).";
}
typedef ip-address {
type union {
type ipv4-address;
type ipv6-address;
}
description
"An IPv4 or IPv6 address with no prefix specified.";
}
typedef ip-address-zoned {
type union {
type ipv4-address-zoned;
type ipv6-address-zoned;
}
description
"An IPv4 or IPv6 address with no prefix specified and an optional
zone index.";
}
typedef ip-prefix {
type union {
type ipv4-prefix;
type ipv6-prefix;
}
description
"An IPv4 or IPv6 prefix.";
}
typedef ip-version {
type enumeration {
enum UNKNOWN {
value 0;
description
"An unknown or unspecified version of the Internet
protocol.";
}
enum IPV4 {
value 4;
description
"The IPv4 protocol as defined in RFC 791.";
}
enum IPV6 {
value 6;
description
"The IPv6 protocol as defined in RFC 2460.";
}
}
description
"This value represents the version of the IP protocol.
Note that integer representation of the enumerated values
are not specified, and are not required to follow the
InetVersion textual convention in SMIv2.";
reference
"RFC 791: Internet Protocol
RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
RFC 4001: Textual Conventions for Internet Network Addresses";
}
typedef ipv6-address-type {
type enumeration {
enum GLOBAL_UNICAST {
description
"The IPv6 address is a global unicast address type and must be in
the format defined in RFC 4291 section 2.4.";
}
enum LINK_LOCAL_UNICAST {
description
"The IPv6 address is a Link-Local unicast address type and must be
in the format defined in RFC 4291 section 2.4.";
}
}
description
"The value represents the type of IPv6 address";
reference
"RFC 4291: IP Version 6 Addressing Architecture
section 2.5";
}
typedef domain-name {
type string {
length "1..253";
pattern
'(((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*' +
'([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)' +
'|\.)';
oc-ext:posix-pattern
'^(((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*' +
'([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)' +
'|\.)$';
}
description
"The domain-name type represents a DNS domain name.
Fully quallified left to the models which utilize this type.
Internet domain names are only loosely specified. Section
3.5 of RFC 1034 recommends a syntax (modified in Section
2.1 of RFC 1123). The pattern above is intended to allow
for current practice in domain name use, and some possible
future expansion. It is designed to hold various types of
domain names, including names used for A or AAAA records
(host names) and other records, such as SRV records. Note
that Internet host names have a stricter syntax (described
in RFC 952) than the DNS recommendations in RFCs 1034 and
1123, and that systems that want to store host names in
schema nodes using the domain-name type are recommended to
adhere to this stricter standard to ensure interoperability.
The encoding of DNS names in the DNS protocol is limited
to 255 characters. Since the encoding consists of labels
prefixed by a length bytes and there is a trailing NULL
byte, only 253 characters can appear in the textual dotted
notation.
Domain-name values use the US-ASCII encoding. Their canonical
format uses lowercase US-ASCII characters. Internationalized
domain names MUST be encoded in punycode as described in RFC
3492";
}
typedef host {
type union {
type ip-address;
type domain-name;
}
description
"The host type represents either an unzoned IP address or a DNS
domain name.";
}
typedef as-number {
type uint32;
description
"A numeric identifier for an autonomous system (AS). An AS is a
single domain, under common administrative control, which forms
a unit of routing policy. Autonomous systems can be assigned a
2-byte identifier, or a 4-byte identifier which may have public
or private scope. Private ASNs are assigned from dedicated
ranges. Public ASNs are assigned from ranges allocated by IANA
to the regional internet registries (RIRs).";
reference
"RFC 1930 Guidelines for creation, selection, and registration
of an Autonomous System (AS)
RFC 4271 A Border Gateway Protocol 4 (BGP-4)";
}
typedef dscp {
type uint8 {
range "0..63";
}
description
"A differentiated services code point (DSCP) marking within the
IP header.";
reference
"RFC 2474 Definition of the Differentiated Services Field
(DS Field) in the IPv4 and IPv6 Headers";
}
typedef ipv6-flow-label {
type uint32 {
range "0..1048575";
}
description
"The IPv6 flow-label is a 20-bit value within the IPv6 header
which is optionally used by the source of the IPv6 packet to
label sets of packets for which special handling may be
required.";
reference
"RFC 2460 Internet Protocol, Version 6 (IPv6) Specification";
}
typedef port-number {
type uint16;
description
"A 16-bit port number used by a transport protocol such as TCP
or UDP.";
reference
"RFC 768 User Datagram Protocol
RFC 793 Transmission Control Protocol";
}
typedef uri {
type string;
description
"An ASCII-encoded Uniform Resource Identifier (URI) as defined
in RFC 3986.";
reference
"RFC 3986 Uniform Resource Identifier (URI): Generic Syntax";
}
typedef url {
type string;
description
"An ASCII-encoded Uniform Resource Locator (URL) as defined
in RFC 3986, section 1.1.3";
reference
"RFC 3986, paragraph 1.1.3";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,548 @@
module openconfig-mpls-types {
yang-version "1";
// namespace
namespace "http://openconfig.net/yang/mpls-types";
prefix "oc-mplst";
import openconfig-extensions { prefix oc-ext; }
// meta
organization "OpenConfig working group";
contact
"OpenConfig working group
netopenconfig@googlegroups.com";
description
"General types for MPLS / TE data model";
oc-ext:openconfig-version "3.5.0";
revision "2023-12-14" {
description
"Added additional attributes oc-if:interface-ref
and metric attributes to static lsp";
reference "3.5.0";
}
revision "2021-12-01" {
description
"Add new identity for RSVP authentication types";
reference "3.4.0";
}
revision "2021-06-16" {
description
"Remove trailing whitespace";
reference "3.3.1";
}
revision "2021-03-23" {
description
"Add new identity for path metric types.";
reference "3.3.0";
}
revision "2020-02-04" {
description
"Consistent prefix for openconfig-mpls-types.";
reference "3.2.0";
}
revision "2019-03-26" {
description
"Add Pseudowire encapsulation.";
reference "3.1.0";
}
revision "2018-11-21" {
description
"Add OpenConfig module metadata extensions.";
reference "3.0.1";
}
revision "2018-07-02" {
description
"Add new RSVP-TE statistics, remove associated-rsvp-session
leaf. Remove use of date-and-time.";
reference "3.0.0";
}
revision "2018-06-16" {
description
"Included attributes for base LDP configuration.";
reference "2.6.0";
}
revision "2018-06-13" {
description
"Add ttl-propagation to global MPLS config";
reference "2.5.0";
}
revision "2018-06-05" {
description
"Fixed bugs in when statements on RSVP-TE attributes";
reference "2.4.2";
}
revision "2017-08-24" {
description
"Minor formatting fixes.";
reference "2.4.1";
}
revision "2017-06-21" {
description
"Add TC bits typedef.";
reference "2.4.0";
}
revision "2017-03-22" {
description
"Add RSVP calculated-absolute-subscription-bw";
reference "2.3.0";
}
revision "2017-01-26" {
description
"Add RSVP Tspec, clarify units for RSVP, remove unused LDP";
reference "2.2.0";
}
revision "2016-12-15" {
description
"Add additional MPLS parameters";
reference "2.1.0";
}
revision "2016-09-01" {
description
"Revisions based on implementation feedback";
reference "2.0.0";
}
revision "2016-08-08" {
description
"Public release of MPLS models";
reference "1.0.1";
}
// identity statements
identity PATH_COMPUTATION_METHOD {
description
"base identity for supported path computation
mechanisms";
}
identity LOCALLY_COMPUTED {
base PATH_COMPUTATION_METHOD;
description
"indicates a constrained-path LSP in which the
path is computed by the local LER";
}
identity EXTERNALLY_QUERIED {
base PATH_COMPUTATION_METHOD;
description
"Constrained-path LSP in which the path is
obtained by querying an external source, such as a PCE server.
In the case that an LSP is defined to be externally queried, it may
also have associated explicit definitions (which are provided to the
external source to aid computation); and the path that is returned by
the external source is not required to provide a wholly resolved
path back to the originating system - that is to say, some local
computation may also be required";
}
identity EXPLICITLY_DEFINED {
base PATH_COMPUTATION_METHOD;
description
"constrained-path LSP in which the path is
explicitly specified as a collection of strict or/and loose
hops";
}
// using identities rather than enum types to simplify adding new
// signaling protocols as they are introduced and supported
identity PATH_SETUP_PROTOCOL {
description
"base identity for supported MPLS signaling
protocols";
}
identity PATH_SETUP_RSVP {
base PATH_SETUP_PROTOCOL;
description
"RSVP-TE signaling protocol";
}
identity PATH_SETUP_SR {
base PATH_SETUP_PROTOCOL;
description
"Segment routing";
}
identity PATH_SETUP_LDP {
base PATH_SETUP_PROTOCOL;
description
"LDP - RFC 5036";
}
identity PROTECTION_TYPE {
description
"base identity for protection type";
}
identity UNPROTECTED {
base PROTECTION_TYPE;
description
"no protection is desired";
}
identity LINK_PROTECTION_REQUIRED {
base PROTECTION_TYPE;
description
"link protection is desired";
}
identity LINK_NODE_PROTECTION_REQUESTED {
base PROTECTION_TYPE;
description
"node and link protection are both desired";
}
identity LSP_ROLE {
description
"Base identity for describing the role of
label switched path at the current node";
}
identity INGRESS {
base LSP_ROLE;
description
"Label switched path is an ingress (headend)
LSP";
}
identity EGRESS {
base LSP_ROLE;
description
"Label switched path is an egress (tailend)
LSP";
}
identity TRANSIT {
base LSP_ROLE;
description
"Label switched path is a transit LSP";
}
identity TUNNEL_TYPE {
description
"Base identity from which specific tunnel types are
derived.";
}
identity P2P {
base TUNNEL_TYPE;
description
"TE point-to-point tunnel type.";
}
identity P2MP {
base TUNNEL_TYPE;
description
"TE point-to-multipoint tunnel type.";
}
identity LSP_OPER_STATUS {
description
"Base identity for LSP operational status";
}
identity DOWN {
base LSP_OPER_STATUS;
description
"LSP is operationally down or out of service";
}
identity UP {
base LSP_OPER_STATUS;
description
"LSP is operationally active and available
for traffic.";
}
identity TUNNEL_ADMIN_STATUS {
description
"Base identity for tunnel administrative status";
}
identity ADMIN_DOWN {
base TUNNEL_ADMIN_STATUS;
description
"LSP is administratively down";
}
identity ADMIN_UP {
base TUNNEL_ADMIN_STATUS;
description
"LSP is administratively up";
}
identity NULL_LABEL_TYPE {
description
"Base identity from which specific null-label types are
derived.";
}
identity EXPLICIT {
base NULL_LABEL_TYPE;
description
"Explicit null label is used.";
}
identity IMPLICIT {
base NULL_LABEL_TYPE;
description
"Implicit null label is used.";
}
identity LSP_METRIC_TYPE {
description
"Base identity for types of LSP metric specification";
}
identity LSP_METRIC_RELATIVE {
base LSP_METRIC_TYPE;
description
"The metric specified for the LSPs to which this identity refers
is specified as a relative value to the IGP metric cost to the
LSP's tail-end.";
}
identity LSP_METRIC_ABSOLUTE {
base LSP_METRIC_TYPE;
description
"The metric specified for the LSPs to which this identity refers
is specified as an absolute value";
}
identity LSP_METRIC_INHERITED {
base LSP_METRIC_TYPE;
description
"The metric for for the LSPs to which this identity refers is
not specified explicitly - but rather inherited from the IGP
cost directly";
}
// Note: The IANA PWE3 Types Registry has several more values than these
identity PSEUDOWIRE_ENCAPSULATION {
description
"Sets the PDU type of the PSEUDOWIRE Example in RFC4448. This value
should be enumerated from the IANA Pseudowire types registry";
}
identity PWE_ETHERNET_TAGGED_MODE {
base PSEUDOWIRE_ENCAPSULATION;
description
"Ethernet Tagged Mode RFC4448";
reference "IANA PWE3 0x0004";
}
identity PWE_ETHERNET_RAW_MODE {
base PSEUDOWIRE_ENCAPSULATION;
description
"Ethernet Raw Mode RFC4448";
reference "IANA PWE3 0x0005";
}
identity PATH_METRIC_TYPE {
description
"Base identity for path metric type.";
}
identity TE_METRIC {
base PATH_METRIC_TYPE;
description
"TE path metric.";
reference
"RFC3785: Use of Interior Gateway Protocol (IGP) Metric as a
second MPLS Traffic Engineering (TE) Metric.
RFC5440: Path Computation Element (PCE) Communication Protocol (PCEP).";
}
identity IGP_METRIC {
base PATH_METRIC_TYPE;
description
"IGP path metric.";
reference
"RFC5440: Path Computation Element (PCE) Communication Protocol (PCEP).";
}
identity HOP_COUNT {
base PATH_METRIC_TYPE;
description
"Hop count path metric.";
reference
"RFC5440: Path Computation Element (PCE) Communication Protocol (PCEP).";
}
identity PATH_DELAY {
base PATH_METRIC_TYPE;
description
"Unidirectional average link delay.
It represents the sum of the Link Delay metric
of all links along a P2P path.";
reference
"RFC8570 IS-IS Traffic Engineering (TE) Metric Extensions.
RFC7471 OSPF Traffic Engineering (TE) Metric Extensions.
RFC 8233: Extensions to the Path Computation Element Communication Protocol (PCEP)
to Compute Service-Aware Label Switched Paths (LSPs) Path Computation Element (PCE)
Communication Protocol (PCEP).";
}
identity RSVP_AUTH_TYPE {
description
"Base identity for RSVP message authentication types";
reference
"RFC2747: RSVP Cryptographic Authentication";
}
identity RSVP_AUTH_MD5 {
base RSVP_AUTH_TYPE;
description
"HMAC-MD5 message authentication";
}
// typedef statements
typedef mpls-label {
type union {
type uint32 {
range 16..1048575;
}
type enumeration {
enum IPV4_EXPLICIT_NULL {
value 0;
description
"valid at the bottom of the label stack,
indicates that stack must be popped and packet forwarded
based on IPv4 header";
}
enum ROUTER_ALERT {
value 1;
description
"allowed anywhere in the label stack except
the bottom, local router delivers packet to the local CPU
when this label is at the top of the stack";
}
enum IPV6_EXPLICIT_NULL {
value 2;
description
"valid at the bottom of the label stack,
indicates that stack must be popped and packet forwarded
based on IPv6 header";
}
enum IMPLICIT_NULL {
value 3;
description
"assigned by local LSR but not carried in
packets";
}
enum ENTROPY_LABEL_INDICATOR {
value 7;
description
"Entropy label indicator, to allow an LSR
to distinguish between entropy label and applicaiton
labels RFC 6790";
}
enum NO_LABEL {
description
"This value is utilised to indicate that the packet that
is forwarded by the local system does not have an MPLS
header applied to it. Typically, this is used at the
egress of an LSP";
}
}
}
description
"type for MPLS label value encoding";
reference "RFC 3032 - MPLS Label Stack Encoding";
}
typedef tunnel-type {
type enumeration {
enum P2P {
description
"point-to-point label-switched-path";
}
enum P2MP {
description
"point-to-multipoint label-switched-path";
}
enum MP2MP {
description
"multipoint-to-multipoint label-switched-path";
}
}
description
"defines the tunnel type for the LSP";
reference
"RFC 6388 - Label Distribution Protocol Extensions for
Point-to-Multipoint and Multipoint-to-Multipoint Label Switched
Paths
RFC 4875 - Extensions to Resource Reservation Protocol
- Traffic Engineering (RSVP-TE) for Point-to-Multipoint TE
Label Switched Paths (LSPs)";
}
typedef bandwidth-kbps {
type uint64;
units "Kbps";
description
"Bandwidth values expressed in kilobits per second";
}
typedef bandwidth-mbps {
type uint64;
units "Mbps";
description
"Bandwidth values expressed in megabits per second";
}
typedef bandwidth-gbps {
type uint64;
units "Gbps";
description
"Bandwidth values expressed in gigabits per second";
}
typedef mpls-tc {
type uint8 {
range "0..7";
}
description
"Values of the MPLS Traffic Class (formerly known as
Experimental, EXP) bits";
}
// grouping statements
// data definition statements
// augment statements
// rpc statements
// notification statements
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,374 @@
module openconfig-packet-match-types {
yang-version "1";
// namespace
namespace "http://openconfig.net/yang/packet-match-types";
prefix "oc-pkt-match-types";
// import some basic types
import openconfig-inet-types { prefix oc-inet; }
import openconfig-extensions { prefix oc-ext; }
// meta
organization "OpenConfig working group";
contact
"OpenConfig working group
www.openconfig.net";
description
"This module defines common types for use in models requiring
data definitions related to packet matches.";
oc-ext:openconfig-version "1.3.3";
revision "2023-01-29" {
description
"Whitespace cleanup.";
reference "1.3.3";
}
revision "2021-07-14" {
description
"Use auto-generated regex for port-num-range pattern statements";
reference "1.3.2";
}
revision "2021-06-16" {
description
"Remove trailing whitespace.";
reference "1.3.1";
}
revision "2021-05-19" {
description
"Add IP-in-IP protocol.";
reference "1.3.0";
}
revision "2021-03-17" {
description
"Add MPLS filter Support.";
reference "1.2.0";
}
revision "2021-01-07" {
description
"Remove module extension oc-ext:regexp-posix by making pattern regexes
conform to RFC7950.
Types impacted:
- port-num-range";
reference "1.1.0";
}
revision "2020-10-20" {
description
"Fix pattern regex for port-num-range.";
reference "1.0.4";
}
revision "2020-06-30" {
description
"Add OpenConfig POSIX pattern extensions.";
reference "1.0.3";
}
revision "2018-11-21" {
description
"Add OpenConfig module metadata extensions.";
reference "1.0.2";
}
revision "2018-04-15" {
description
"Corrected description and range for ethertype typedef";
reference "1.0.1";
}
revision "2017-05-26" {
description
"Separated IP matches into AFs";
reference "1.0.0";
}
revision "2016-08-08" {
description
"OpenConfig public release";
reference "0.2.0";
}
revision "2016-04-27" {
description
"Initial revision";
reference "TBD";
}
// OpenConfig specific extensions for module metadata.
oc-ext:catalog-organization "openconfig";
oc-ext:origin "openconfig";
// extension statements
// feature statements
// identity statements
//TODO: should replace this with an official IEEE module
// when available. Only a select number of types are
// defined in this identity.
identity ETHERTYPE {
description
"Base identity for commonly used Ethertype values used
in packet header matches on Ethernet frames. The Ethertype
indicates which protocol is encapsulated in the Ethernet
payload.";
reference
"IEEE 802.3";
}
identity ETHERTYPE_IPV4 {
base ETHERTYPE;
description
"IPv4 protocol (0x0800)";
}
identity ETHERTYPE_ARP {
base ETHERTYPE;
description
"Address resolution protocol (0x0806)";
}
identity ETHERTYPE_VLAN {
base ETHERTYPE;
description
"VLAN-tagged frame (as defined by IEEE 802.1q) (0x8100). Note
that this value is also used to represent Shortest Path
Bridging (IEEE 801.1aq) frames.";
}
identity ETHERTYPE_IPV6 {
base ETHERTYPE;
description
"IPv6 protocol (0x86DD)";
}
identity ETHERTYPE_MPLS {
base ETHERTYPE;
description
"MPLS unicast (0x8847)";
}
identity ETHERTYPE_LLDP {
base ETHERTYPE;
description
"Link Layer Discovery Protocol (0x88CC)";
}
identity ETHERTYPE_ROCE {
base ETHERTYPE;
description
"RDMA over Converged Ethernet (0x8915)";
}
//TODO: should replace this with an official IANA module when
//available. Only a select set of protocols are defined with
//this identity.
identity IP_PROTOCOL {
description
"Base identity for commonly used IP protocols used in
packet header matches";
reference
"IANA Assigned Internet Protocol Numbers";
}
identity IP_TCP {
base IP_PROTOCOL;
description
"Transmission Control Protocol (6)";
}
identity IP_UDP {
base IP_PROTOCOL;
description
"User Datagram Protocol (17)";
}
identity IP_ICMP {
base IP_PROTOCOL;
description
"Internet Control Message Protocol (1)";
}
identity IP_IGMP {
base IP_PROTOCOL;
description
"Internet Group Membership Protocol (2)";
}
identity IP_PIM {
base IP_PROTOCOL;
description
"Protocol Independent Multicast (103)";
}
identity IP_RSVP {
base IP_PROTOCOL;
description
"Resource Reservation Protocol (46)";
}
identity IP_GRE {
base IP_PROTOCOL;
description
"Generic Routing Encapsulation (47)";
}
identity IP_AUTH {
base IP_PROTOCOL;
description
"Authentication header, e.g., for IPSEC (51)";
}
identity IP_L2TP {
base IP_PROTOCOL;
description
"Layer Two Tunneling Protocol v.3 (115)";
}
identity IP_IN_IP {
base IP_PROTOCOL;
description
"IP-in-IP tunneling (4)";
reference
"RFC2003: IP Encapsulation within IP";
}
identity TCP_FLAGS {
description
"Common TCP flags used in packet header matches";
reference
"IETF RFC 793 - Transmission Control Protocol
IETF RFC 3168 - The Addition of Explicit Congestion
Notification (ECN) to IP";
}
identity TCP_SYN {
base TCP_FLAGS;
description
"TCP SYN flag";
}
identity TCP_FIN {
base TCP_FLAGS;
description
"TCP FIN flag";
}
identity TCP_RST {
base TCP_FLAGS;
description
"TCP RST flag";
}
identity TCP_PSH {
base TCP_FLAGS;
description
"TCP push flag";
}
identity TCP_ACK {
base TCP_FLAGS;
description
"TCP ACK flag";
}
identity TCP_URG {
base TCP_FLAGS;
description
"TCP urgent flag";
}
identity TCP_ECE {
base TCP_FLAGS;
description
"TCP ECN-Echo flag. If the SYN flag is set, indicates that
the TCP peer is ECN-capable, otherwise indicates that a
packet with Congestion Experienced flag in the IP header
is set";
}
identity TCP_CWR {
base TCP_FLAGS;
description
"TCP Congestion Window Reduced flag";
}
// typedef statements
typedef port-num-range {
type union {
type string {
pattern
'(0{0,4}[0-9]|0{0,3}[1-9][0-9]|0{0,2}[1-9][0-9]{2}|'
+ '0?[1-9][0-9]{3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|'
+ '655[0-2][0-9]|6553[0-5])\.\.(0{0,4}[0-9]|0{0,3}[1-9][0-9]|'
+ '0{0,2}[1-9][0-9]{2}|0?[1-9][0-9]{3}|[1-5][0-9]{4}|'
+ '6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])';
oc-ext:posix-pattern
'^((0{0,4}[0-9]|0{0,3}[1-9][0-9]|0{0,2}[1-9][0-9]{2}|'
+ '0?[1-9][0-9]{3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|'
+ '655[0-2][0-9]|6553[0-5])\.\.(0{0,4}[0-9]|0{0,3}[1-9][0-9]|'
+ '0{0,2}[1-9][0-9]{2}|0?[1-9][0-9]{3}|[1-5][0-9]{4}|'
+ '6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))$';
}
type oc-inet:port-number;
type enumeration {
enum ANY {
description
"Indicates any valid port number (e.g., wildcard)";
}
}
}
description
"Port numbers may be represented as a single value,
an inclusive range as <lower>..<higher>, or as ANY to
indicate a wildcard.";
}
typedef ip-protocol-type {
type union {
type uint8 {
range 0..254;
}
type identityref {
base IP_PROTOCOL;
}
}
description
"The IP protocol number may be expressed as a valid protocol
number (integer) or using a protocol type defined by the
IP_PROTOCOL identity";
}
typedef ethertype-type {
type union {
type uint16 {
range 1536..65535;
}
type identityref {
base ETHERTYPE;
}
}
description
"The Ethertype value may be expressed as a 16-bit number in
decimal notation, or using a type defined by the
ETHERTYPE identity";
}
}

View File

@@ -0,0 +1,727 @@
module openconfig-packet-match {
yang-version "1";
// namespace
namespace "http://openconfig.net/yang/header-fields";
prefix "oc-pkt-match";
// import some basic types
import openconfig-inet-types { prefix oc-inet; }
import openconfig-yang-types { prefix oc-yang; }
import openconfig-packet-match-types { prefix oc-pkt-match-types; }
import openconfig-extensions { prefix oc-ext; }
import openconfig-mpls-types { prefix oc-mpls; }
import openconfig-defined-sets { prefix oc-sets; }
import openconfig-icmpv4-types { prefix oc-icmpv4-types; }
import openconfig-icmpv6-types { prefix oc-icmpv6-types; }
// meta
organization "OpenConfig working group";
contact
"OpenConfig working group
www.openconfig.net";
description
"This module defines data related to packet header fields
used in matching operations, for example in ACLs. When a
field is omitted from a match expression, the effect is a
wildcard ('any') for that field.";
oc-ext:openconfig-version "2.1.0";
revision "2023-03-01" {
description
"Add ICMP Fields for filtering.";
reference "2.1.0";
}
revision "2023-01-27" {
description
"Update the mechanism to match detailed transport flags,
adding means for AND/OR in the explicitly specified flags
and commonly supported match aliases.";
reference "2.0.0";
}
revision "2022-06-01" {
description
"Add the ability to match source/destination ipv4 and
ipv6 prefix list and source/destination port list ";
reference "1.4.0";
}
revision "2021-06-16" {
description
"Remove trailing whitespace.";
reference "1.3.1";
}
revision "2021-05-19" {
description
"Add the ability to match multiple DSCPs in a rule.";
reference "1.3.0";
}
revision "2021-03-17" {
description
"Add MPLS filter Support.";
reference "1.2.0";
}
revision "2018-11-21" {
description
"Add OpenConfig module metadata extensions.";
reference "1.1.1";
}
revision "2017-12-15" {
description
"Add MPLS packet field matches";
reference "1.1.0";
}
revision "2017-05-26" {
description
"Separated IP matches into AFs";
reference "1.0.0";
}
revision "2016-08-08" {
description
"OpenConfig public release";
reference "0.2.0";
}
revision "2016-04-27" {
description
"Initial revision";
reference "TBD";
}
// OpenConfig specific extensions for module metadata.
oc-ext:regexp-posix;
oc-ext:catalog-organization "openconfig";
oc-ext:origin "openconfig";
// Physical Layer fields
// ethernet-header
grouping ethernet-header-config {
description
"Configuration data of fields in Ethernet header.";
leaf source-mac {
type oc-yang:mac-address;
description
"Source IEEE 802 MAC address.";
}
leaf source-mac-mask {
type oc-yang:mac-address;
description
"Source IEEE 802 MAC address mask.";
}
leaf destination-mac {
type oc-yang:mac-address;
description
"Destination IEEE 802 MAC address.";
}
leaf destination-mac-mask {
type oc-yang:mac-address;
description
"Destination IEEE 802 MAC address mask.";
}
leaf ethertype {
type oc-pkt-match-types:ethertype-type;
description
"Ethertype field to match in Ethernet packets";
}
}
grouping ethernet-header-state {
description
"State information of fields in Ethernet header.";
}
grouping ethernet-header-top {
description
"Top level container for fields in Ethernet header.";
container l2 {
description
"Ethernet header fields";
container config {
description
"Configuration data";
uses ethernet-header-config;
}
container state {
config false;
description
"State Information.";
uses ethernet-header-config;
uses ethernet-header-state;
}
}
}
grouping mpls-header-top {
description
"Top-level container for fields in an MPLS header.";
container mpls {
description
"MPLS header fields";
container config {
description
"Configuration parameters relating to fields within
the MPLS header.";
uses mpls-header-config;
}
container state {
config false;
description
"Operational state parameters relating to fields
within the MPLS header";
uses mpls-header-config;
}
}
}
grouping mpls-header-config {
description
"Configuration parameters relating to matches within
MPLS header fields.";
leaf traffic-class {
type oc-mpls:mpls-tc;
description
"The value of the MPLS traffic class (TC) bits,
formerly known as the EXP bits.";
}
leaf start-label-value {
type oc-mpls:mpls-label;
description
"Match MPLS label value on the MPLS header.
The usage of this field indicated the upper
range value in the top of the stack.
The range that is used is inclusive. The match that
is done for a particular received pkt_label is:
start-label-value <= pkt_label <= end-label-value.
The 20-bit label value in an MPLS label
stack as specified in RFC 3032.
This label value does not include the
encodings of Traffic Class and TTL.";
}
leaf end-label-value {
type oc-mpls:mpls-label;
description
"Match MPLS label value on the MPLS header.
The usage of this field indicated the upper
range value in the top of the stack.
The range that is used is inclusive. The match that
is done for a particular received pkt_label is:
start-label-value <= pkt_label <= end-label-value.
The 20-bit label value in an MPLS label
stack as specified in RFC 3032.
This label value does not include the
encodings of Traffic Class and TTL.";
}
leaf ttl-value {
type uint8;
description
"Time-to-live MPLS packet value match.";
reference
"RFC 3032: MPLS Label Stack Encoding.";
}
}
grouping ip-protocol-fields-common-config {
description
"IP protocol fields common to IPv4 and IPv6";
leaf dscp {
type oc-inet:dscp;
description
"Value of diffserv codepoint.";
}
leaf-list dscp-set {
type oc-inet:dscp;
description
"A list of DSCP values to be matched for incoming packets. AN OR match should
be performed, such that a packet must match one of the values defined in this
list. If the field is left empty then any DSCP value matches unless the 'dscp'
leaf is specified. It is not valid to specify both 'dscp' and 'dscp-set together.'";
}
leaf length {
type uint16;
description
"In the IPv4 header field, this field is known as the Total
Length. Total Length is the length of the datagram, measured
in octets, including internet header and data.
In the IPv6 header field, this field is known as the Payload
Length, which is the length of the IPv6 payload, i.e., the rest
of the packet following the IPv6 header, in octets.";
reference
"RFC 791: Internet Protocol
RFC 8200: Internet Protocol, Version 6 (IPv6) Specification.";
}
leaf protocol {
type oc-pkt-match-types:ip-protocol-type;
description
"The protocol carried in the IP packet, expressed either
as its IP protocol number, or by a defined identity.";
}
leaf hop-limit {
type uint8 {
range 0..255;
}
description
"The IP packet's hop limit -- known as TTL (in hops) in
IPv4 packets, and hop limit in IPv6";
}
}
// IP Layer
// ip-protocol-fields
grouping ipv4-protocol-fields-config {
description
"Configuration data of IP protocol fields
for IPv4";
leaf source-address {
type oc-inet:ipv4-prefix;
description
"Source IPv4 address prefix.";
}
leaf source-address-prefix-set {
type leafref {
path "/oc-sets:defined-sets/oc-sets:ipv4-prefix-sets"
+ "/oc-sets:ipv4-prefix-set/oc-sets:name";
}
description
"Reference to a IPv4 address prefix Set
to match the source address";
}
leaf destination-address {
type oc-inet:ipv4-prefix;
description
"Destination IPv4 address prefix.";
}
leaf destination-address-prefix-set {
type leafref {
path "/oc-sets:defined-sets/oc-sets:ipv4-prefix-sets"
+ "/oc-sets:ipv4-prefix-set/oc-sets:name";
}
description
"Reference to a IPv4 address prefix set
to match the destination address";
}
uses ip-protocol-fields-common-config;
}
grouping ipv4-protocol-fields-state {
description
"State information of IP header fields for IPv4";
}
grouping ipv4-protocol-fields-top {
description
"IP header fields for IPv4";
container ipv4 {
description
"Top level container for IPv4 match field data";
container config {
description
"Configuration data for IPv4 match fields";
uses ipv4-protocol-fields-config;
}
container state {
config false;
description
"State information for IPv4 match fields";
uses ipv4-protocol-fields-config;
uses ipv4-protocol-fields-state;
}
uses ip-icmpv4-header-fields-top;
}
}
grouping ipv6-protocol-fields-config {
description
"Configuration data for IPv6 match fields";
leaf source-address {
type oc-inet:ipv6-prefix;
description
"Source IPv6 address prefix.";
}
leaf source-address-prefix-set {
type leafref {
path "/oc-sets:defined-sets/oc-sets:ipv6-prefix-sets"
+ "/oc-sets:ipv6-prefix-set/oc-sets:name";
}
description
"Reference to a IPv6 address prefix set
to match the source address";
}
leaf source-flow-label {
type oc-inet:ipv6-flow-label;
description
"Source IPv6 Flow label.";
}
leaf destination-address {
type oc-inet:ipv6-prefix;
description
"Destination IPv6 address prefix.";
}
leaf destination-address-prefix-set {
type leafref {
path "/oc-sets:defined-sets/oc-sets:ipv6-prefix-sets"
+ "/oc-sets:ipv6-prefix-set/oc-sets:name";
}
description
"Reference to a IPv6 address prefix set
to match the destination address";
}
leaf destination-flow-label {
type oc-inet:ipv6-flow-label;
description
"Destination IPv6 Flow label.";
}
uses ip-protocol-fields-common-config;
}
grouping ipv6-protocol-fields-state {
description
"Operational state data for IPv6 match fields";
}
grouping ipv6-protocol-fields-top {
description
"Top-level grouping for IPv6 match fields";
container ipv6 {
description
"Top-level container for IPv6 match field data";
container config {
description
"Configuration data for IPv6 match fields";
uses ipv6-protocol-fields-config;
}
container state {
config false;
description
"Operational state data for IPv6 match fields";
uses ipv6-protocol-fields-config;
uses ipv6-protocol-fields-state;
}
uses ip-icmpv6-header-fields-top;
}
}
// Transport fields
grouping transport-fields-config {
description
"Configuration data of transport-layer packet fields";
leaf source-port {
type oc-pkt-match-types:port-num-range;
description
"Source port or range";
}
leaf source-port-set {
type leafref {
path "/oc-sets:defined-sets/oc-sets:port-sets"
+ "/oc-sets:port-set/oc-sets:name";
}
description
"Reference to a port set
to match the source port";
}
leaf destination-port {
type oc-pkt-match-types:port-num-range;
description
"Destination port or range";
}
leaf destination-port-set {
type leafref {
path "/oc-sets:defined-sets/oc-sets:port-sets"
+ "/oc-sets:port-set/oc-sets:name";
}
description
"Reference to a port set
to match the destination port";
}
leaf detail-mode {
type enumeration {
enum EXPLICIT {
description
"Specifies that the mode for matching details at the transport
layer is to explicitly match transport flags.";
}
enum BUILTIN {
description
"Specifies that the mode for matching details at the transport
layer is to using implementation built-ins which may map to
multiple flags.";
}
}
description
"Mode that is used for matching detailed fields at the transport
layer. When EXPLICIT is specified, the implementation should
match based on the explicit flags that are specified in the
corresponding leaf. When BUILTIN is specified, the implementation
must expand the contents of the corresponding leaf to the flags
and/or fields that match the pre-defined built-in values.";
}
leaf explicit-detail-match-mode {
type enumeration {
enum ANY {
description
"Matches of the explicit-detail-flags field are treated as
an OR between the values in the list.";
}
enum ALL {
description
"Matches of the explicit-details-flags field are treated
as an AND of the values in the list.";
}
}
description
"Specifies how the contents of the explicit-details-flags list
are to be treated. ANY implies that any of the flags may match,
where ALL indicates that all the flags must be matched.";
when "../detail-mode = 'EXPLICIT'" {
description
"This leaf is only valid when the mode for matches is specified to
be explicit.";
}
}
leaf-list explicit-tcp-flags {
type identityref {
base oc-pkt-match-types:TCP_FLAGS;
}
description
"An explicit list of the TCP flags that are to be matched. The
mechanism for the match is specified by the explicit-detail-match-mode
leaf.";
when "../detail-mode = 'EXPLICIT'" {
description
"This leaf is only valid when the mode for matches is specified to
be explicit.";
}
}
leaf builtin-detail {
type enumeration {
enum TCP_INITIAL {
description
"Matches the first packet of a TCP session based on a packet
not having the ACK flag set, and having the SYN flag set.";
}
enum TCP_ESTABLISHED {
description
"Matches an established TCP session based on a packet having
the ACK or RST flags set. This does not match the first
packet.";
}
enum FRAGMENT {
description
"Matches non-zero values of the fragment-offset field, indicating
this packet is a follow up to a fragmented datagram.";
}
}
description
"Specifies a built-in (alias) for a match condition that matches
multiple flags, or specifies particular logic as to the flag matches
to be implemented. This leaf is only valid when the detail-match-mode
leaf is BUILTIN.";
when "../detail-mode = 'BUILTIN'" {
description
"This leaf is only valid when the mode for matches is specified to
be builtin.";
}
}
}
grouping transport-fields-state {
description
"State data of transport-fields";
}
grouping transport-fields-top {
description
"Destination transport-fields top level grouping";
container transport {
description
"Transport fields container";
container config {
description
"Configuration data";
uses transport-fields-config;
}
container state {
config false;
description
"State data";
uses transport-fields-config;
uses transport-fields-state;
}
}
}
grouping ip-icmpv4-header-fields-top {
description
"Top grouping for ICMPv4 filtering";
container icmpv4 {
description
"Top container for ICMPv4 filtering";
container config {
description
"Configuration attributes for ICMPv4 filtering";
uses ip-icmpv4-header-fields-config;
}
container state {
description
"State attributes for ICMPv4 filtering";
config false;
uses ip-icmpv4-header-fields-config;
}
}
}
grouping ip-icmpv6-header-fields-top {
description
"Top grouping for ICMPv6 filtering";
container icmpv6 {
description
"Top container for ICMPv6 filtering";
container config {
description
"Configuration attributes for ICMPv6 filtering";
uses ip-icmpv6-header-fields-config;
}
container state {
description
"State attributes for ICMPv6 filtering";
config false;
uses ip-icmpv6-header-fields-config;
}
}
}
grouping ip-icmpv4-header-fields-config {
description
"Collection of ICMPv4 header fields that can be
used to set up a match filter.";
leaf type {
type identityref {
base oc-icmpv4-types:TYPE;
}
description
"ICMPv4 type to be matched.";
reference
"RFC 792: Internet Control Message Protocol";
}
leaf code {
type identityref {
base oc-icmpv4-types:CODE;
}
description
"ICMPv4 code to be matched.";
reference
"RFC 792: Internet Control Message Protocol";
}
}
grouping ip-icmpv6-header-fields-config {
description
"Collection of ICMPv6 header fields that can be
used to set up a match filter.";
leaf type {
type identityref {
base oc-icmpv6-types:TYPE;
}
description
"ICMPv6 type to be matched.";
reference
"RFC 4443: Internet Control Message Protocol (ICMPv6)
for Internet Protocol Version 6 (IPv6)
Specification.";
}
leaf code {
type identityref {
base oc-icmpv6-types:CODE;
}
description
"ICMP code to be matched.";
reference
"RFC 4443: Internet Control Message Protocol (ICMPv6)
for Internet Protocol Version 6 (IPv6)
Specification.";
}
}
}

View File

@@ -0,0 +1,633 @@
module openconfig-platform-types {
yang-version "1";
// namespace
namespace "http://openconfig.net/yang/platform-types";
prefix "oc-platform-types";
import openconfig-types { prefix oc-types; }
import openconfig-extensions { prefix oc-ext; }
// meta
organization
"OpenConfig working group";
contact
"OpenConfig working group
www.openconfig.net";
description
"This module defines data types (e.g., YANG identities)
to support the OpenConfig component inventory model.";
oc-ext:openconfig-version "1.10.0";
revision "2025-07-09" {
description
"Add FPGA, BOOT_LOADER_GRUB, BOOT_LOADER_ONIE";
reference "1.10.0";
}
revision "2024-11-04" {
description
"Add FAN_TRAY_CONTROLLER";
reference "1.9.0";
}
revision "2024-04-30" {
description
"Add FAN_TRAY";
reference "1.8.0";
}
revision "2024-01-30" {
description
"Add component-last-poweroff-reason grouping";
reference "1.7.0";
}
revision "2023-06-27" {
description
"Add WIFI_ACCESS_POINT";
reference "1.6.0";
}
revision "2022-07-28" {
description
"Add grouping for component power management";
reference "1.5.0";
}
revision "2022-03-27" {
description
"Add identity for BIOS";
reference "1.4.0";
}
revision "2022-02-02" {
description
"Add support for component reboot and switchover.";
reference "1.3.0";
}
revision "2021-07-29" {
description
"Add several avg-min-max-instant-stats groupings";
reference "1.2.0";
}
revision "2021-01-18" {
description
"Add identity for software modules";
reference "1.1.0";
}
revision "2019-06-03" {
description
"Add OpenConfig component operating system patch type.";
reference "1.0.0";
}
revision "2018-11-21" {
description
"Add OpenConfig module metadata extensions.";
reference "0.10.1";
}
revision "2018-11-16" {
description
"Added FEC_MODE_TYPE and FEC_STATUS_TYPE";
reference "0.10.0";
}
revision "2018-05-05" {
description
"Added min-max-time to
avg-min-max-instant-stats-precision1-celsius,
added new CONTROLLER_CARD identity";
reference "0.9.0";
}
revision "2018-01-16" {
description
"Added new per-component common data; add temp alarm";
reference "0.8.0";
}
revision "2017-12-14" {
description
"Added anchor containers for component data, added new
component types";
reference "0.7.0";
}
revision "2017-08-16" {
description
"Added power state enumerated type";
reference "0.6.0";
}
revision "2016-12-22" {
description
"Added temperature state variable to component";
reference "0.5.0";
}
// OpenConfig specific extensions for module metadata.
oc-ext:regexp-posix;
oc-ext:catalog-organization "openconfig";
oc-ext:origin "openconfig";
// grouping statements
grouping avg-min-max-instant-stats-precision1-celsius {
description
"Common grouping for recording temperature values in
Celsius with 1 decimal precision. Values include the
instantaneous, average, minimum, and maximum statistics";
leaf instant {
type decimal64 {
fraction-digits 1;
}
units celsius;
description
"The instantaneous value of the statistic.";
}
leaf avg {
type decimal64 {
fraction-digits 1;
}
units celsius;
description
"The arithmetic mean value of the statistic over the
sampling period.";
}
leaf min {
type decimal64 {
fraction-digits 1;
}
units celsius;
description
"The minimum value of the statistic over the sampling
period";
}
leaf max {
type decimal64 {
fraction-digits 1;
}
units celsius;
description
"The maximum value of the statistic over the sampling
period";
}
uses oc-types:stat-interval-state;
uses oc-types:min-max-time;
}
grouping avg-min-max-instant-stats-precision2-volts {
description
"Common grouping for recording voltage values in
volts with 2 decimal precision. Values include the
instantaneous, average, minimum, and maximum statistics.
If supported by the device, the time interval over which
the statistics are computed, and the times at which the
minimum and maximum values occurred, are also reported.";
leaf instant {
type decimal64 {
fraction-digits 2;
}
units volts;
description
"The instantaneous value of the statistic.";
}
leaf avg {
type decimal64 {
fraction-digits 2;
}
units volts;
description
"The arithmetic mean value of the statistic over the
sampling period.";
}
leaf min {
type decimal64 {
fraction-digits 2;
}
units volts;
description
"The minimum value of the statistic over the sampling
period";
}
leaf max {
type decimal64 {
fraction-digits 2;
}
units volts;
description
"The maximum value of the statistic over the sampling
period";
}
uses oc-types:stat-interval-state;
uses oc-types:min-max-time;
}
grouping component-last-poweroff-reason {
description
"Common grouping for recording the reason of a component's
power-off state";
leaf trigger {
type component-last-poweroff-reason-trigger;
description
"Records the generic triggers for the last poweroff
event. Component power-off can be triggered
in various ways,
- USER_INITIATED
- SYSTEM_INITIATED
- POWER_FAILURE
This field is not updated during reboots; those are
tracked in the 'last-reboot-reason' leaf.";
}
leaf details {
type string;
description
"Provides a detailed reason for component power-off.
For system-initiated power-offs, this field can include
specific causes (e.g., critical errors resulting in a
controller-card bootloop).";
}
}
grouping component-redundant-role-switchover-reason {
description
"Common grouping for recording the reason of a component's
redundant role switchover. For example two supervisors in
a device, one as primary the other as secondary, switchover
can happen in different scenarios, e.g. user requested,
system error, priority contention, etc.";
leaf trigger {
type component-redundant-role-switchover-reason-trigger;
description
"Records the generic triggers, e.g. user or system
initiated the switchover.";
}
leaf details {
type string;
description
"Records detailed description of why the switchover happens.
For example, when system initiated the switchover, this leaf
can be used to record the specific reason, e.g. due to critical
errors of the routing daemon in the primary role.";
}
}
// identity statements
identity OPENCONFIG_HARDWARE_COMPONENT {
description
"Base identity for hardware related components in a managed
device. Derived identities are partially based on contents
of the IANA Entity MIB.";
reference
"IANA Entity MIB and RFC 6933";
}
identity OPENCONFIG_SOFTWARE_COMPONENT {
description
"Base identity for software-related components in a managed
device";
}
// hardware types
identity CHASSIS {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Chassis component, typically with multiple slots / shelves";
}
identity BACKPLANE {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Backplane component for aggregating traffic, typically
contained in a chassis component";
}
identity FABRIC {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Interconnect between ingress and egress ports on the
device (e.g., a crossbar switch).";
}
identity POWER_SUPPLY {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Component that is supplying power to the device";
}
identity FAN {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Cooling fan, or could be some other heat-reduction component";
}
identity FAN_TRAY {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Contains multiple fans that work in unison to cool the router components.";
}
identity FAN_TRAY_CONTROLLER {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Controls the fan trays.";
}
identity SENSOR {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Physical sensor, e.g., a temperature sensor in a chassis";
}
identity FRU {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Replaceable hardware component that does not have a more
specific defined schema.";
}
identity LINECARD {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Linecard component, typically inserted into a chassis slot";
}
identity CONTROLLER_CARD {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"A type of linecard whose primary role is management or control
rather than data forwarding.";
}
identity PORT {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Physical port, e.g., for attaching pluggables and networking
cables";
}
identity TRANSCEIVER {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Pluggable module present in a port";
}
identity CPU {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Processing unit, e.g., a management processor";
}
identity STORAGE {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"A storage subsystem on the device (disk, SSD, etc.)";
}
identity INTEGRATED_CIRCUIT {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"A special purpose processing unit, typically for traffic
switching/forwarding (e.g., switching ASIC, NPU, forwarding
chip, etc.)";
}
identity WIFI_ACCESS_POINT {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"A device that attaches to a an Ethernet network and creates a wireless
local area network";
}
identity FPGA {
base OPENCONFIG_HARDWARE_COMPONENT;
description
"Field-Programmable Gate Array (FPGA) is a type of integrated circuit
that can be configured after manufacturing. This type should not be
used to represent a switching ASIC";
}
identity OPERATING_SYSTEM {
base OPENCONFIG_SOFTWARE_COMPONENT;
description
"Operating system running on a component";
}
identity OPERATING_SYSTEM_UPDATE {
base OPENCONFIG_SOFTWARE_COMPONENT;
description
"An operating system update - which should be a subcomponent
of the `OPERATING_SYSTEM` running on a component. An update is
defined to be a set of software changes that are atomically
installed (and uninstalled) together. Multiple updates may be
present for the Operating System. A system should not list all
installed software packages using this type -- but rather
updates that are bundled together as a single installable
item";
}
identity BIOS {
base OPENCONFIG_SOFTWARE_COMPONENT;
description
"Legacy BIOS or UEFI firmware interface responsible for
initializing hardware components and first stage boot loader.";
}
identity BOOT_LOADER {
base OPENCONFIG_SOFTWARE_COMPONENT;
description
"Software layer responsible for loading and booting the
device OS or network OS.";
}
identity SOFTWARE_MODULE {
base OPENCONFIG_SOFTWARE_COMPONENT;
description
"A base identity for software modules installed and/or
running on the device. Modules include user-space programs
and kernel modules that provide specific functionality.
A component with type SOFTWARE_MODULE should also have a
module type that indicates the specific type of software module";
}
identity COMPONENT_OPER_STATUS {
description
"Current operational status of a platform component";
}
identity ACTIVE {
base COMPONENT_OPER_STATUS;
description
"Component is enabled and active (i.e., up)";
}
identity INACTIVE {
base COMPONENT_OPER_STATUS;
description
"Component is enabled but inactive (i.e., down)";
}
identity DISABLED {
base COMPONENT_OPER_STATUS;
description
"Component is administratively disabled.";
}
identity FEC_MODE_TYPE {
description
"Base identity for FEC operational modes.";
}
identity FEC_ENABLED {
base FEC_MODE_TYPE;
description
"FEC is administratively enabled.";
}
identity FEC_DISABLED {
base FEC_MODE_TYPE;
description
"FEC is administratively disabled.";
}
identity FEC_AUTO {
base FEC_MODE_TYPE;
description
"System will determine whether to enable or disable
FEC on a transceiver.";
}
identity FEC_STATUS_TYPE {
description
"Base identity for FEC operational statuses.";
}
identity FEC_STATUS_LOCKED {
base FEC_STATUS_TYPE;
description
"FEC is operationally locked.";
}
identity FEC_STATUS_UNLOCKED {
base FEC_STATUS_TYPE;
description
"FEC is operationally unlocked.";
}
// typedef statements
typedef component-power-type {
type enumeration {
enum POWER_ENABLED {
description
"Enable power on the component";
}
enum POWER_DISABLED {
description
"Disable power on the component";
}
}
description
"A generic type reflecting whether a hardware component
is powered on or off";
}
identity COMPONENT_REBOOT_REASON {
description
"Base entity for component reboot reasons.";
}
identity REBOOT_USER_INITIATED {
base COMPONENT_REBOOT_REASON;
description
"User initiated the reboot of the componenent.";
}
identity REBOOT_POWER_FAILURE {
base COMPONENT_REBOOT_REASON;
description
"The component reboots due to power failure.";
}
identity REBOOT_CRITICAL_ERROR {
base COMPONENT_REBOOT_REASON;
description
"The component reboots due to critical errors.";
}
typedef component-redundant-role {
type enumeration {
enum PRIMARY {
description
"Component is acting the primary role.";
}
enum SECONDARY {
description
"Component is acting the secondary role.";
}
}
description
"A generic type reflecting the component's redundanty role.
For example, a device might have dual supervisors components
for redundant purpose, with one being the primary and the
other secondary.";
}
typedef component-redundant-role-switchover-reason-trigger {
type enumeration {
enum USER_INITIATED {
description
"User initiated the switchover, e.g. via command line.";
}
enum SYSTEM_INITIATED {
description
"The system initiated the switchover, e.g. due to
critical errors in the component of the primar role.";
}
}
description
"Records how the role switchover is triggered.";
}
typedef component-last-poweroff-reason-trigger {
type enumeration {
enum USER_INITIATED {
description
"User initiated the power-off, e.g. via command line.";
}
enum SYSTEM_INITIATED {
description
"The system initiated the power-off, e.g. due to
critical errors in the component of the primary role.";
}
enum POWER_FAILURE {
description
"The last power-off was due to power failure.";
}
}
description
"Records how the last power-off was triggered.";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,485 @@
module openconfig-types {
yang-version "1";
namespace "http://openconfig.net/yang/openconfig-types";
prefix "oc-types";
// import statements
import openconfig-extensions { prefix oc-ext; }
// meta
organization
"OpenConfig working group";
contact
"OpenConfig working group
netopenconfig@googlegroups.com";
description
"This module contains a set of general type definitions that
are used across OpenConfig models. It can be imported by modules
that make use of these types.";
oc-ext:openconfig-version "1.0.0";
revision "2024-01-31" {
description
"Add posix-eregexp type and promote model to version 1.0.0.";
reference "1.0.0";
}
revision "2019-04-16" {
description
"Clarify definition of timeticks64.";
reference "0.6.0";
}
revision "2018-11-21" {
description
"Add OpenConfig module metadata extensions.";
reference "0.5.1";
}
revision "2018-05-05" {
description
"Add grouping of min-max-time and
included them to all stats with min/max/avg";
reference "0.5.0";
}
revision "2018-01-16" {
description
"Add interval to min/max/avg stats; add percentage stat";
reference "0.4.0";
}
revision "2017-08-16" {
description
"Apply fix for ieetfloat32 length parameter";
reference "0.3.3";
}
revision "2017-01-13" {
description
"Add ADDRESS_FAMILY identity";
reference "0.3.2";
}
revision "2016-11-14" {
description
"Correct length of ieeefloat32";
reference "0.3.1";
}
revision "2016-11-11" {
description
"Additional types - ieeefloat32 and routing-password";
reference "0.3.0";
}
revision "2016-05-31" {
description
"OpenConfig public release";
reference "0.2.0";
}
// OpenConfig specific extensions for module metadata.
oc-ext:regexp-posix;
oc-ext:catalog-organization "openconfig";
oc-ext:origin "openconfig";
typedef percentage {
type uint8 {
range "0..100";
}
description
"Integer indicating a percentage value";
}
typedef std-regexp {
type string;
description
"This type definition is a placeholder for a standard
definition of a regular expression that can be utilised in
OpenConfig models. Further discussion is required to
consider the type of regular expressions that are to be
supported. An initial proposal is POSIX compatible.";
}
typedef posix-eregexp {
type string;
description
"This is a string which represents an extended POSIX
regular expression.";
reference "IEEE Std 1003.1-2017";
}
typedef timeticks64 {
type uint64;
units "nanoseconds";
description
"The timeticks64 represents the time, modulo 2^64 in
nanoseconds between two epochs. The leaf using this
type must define the epochs that tests are relative to.";
}
typedef ieeefloat32 {
type binary {
length "4";
}
description
"An IEEE 32-bit floating point number. The format of this number
is of the form:
1-bit sign
8-bit exponent
23-bit fraction
The floating point value is calculated using:
(-1)**S * 2**(Exponent-127) * (1+Fraction)";
}
typedef routing-password {
type string;
description
"This type is indicative of a password that is used within
a routing protocol which can be returned in plain text to the
NMS by the local system. Such passwords are typically stored
as encrypted strings. Since the encryption used is generally
well known, it is possible to extract the original value from
the string - and hence this format is not considered secure.
Leaves specified with this type should not be modified by
the system, and should be returned to the end-user in plain
text. This type exists to differentiate passwords, which
may be sensitive, from other string leaves. It could, for
example, be used by the NMS to censor this data when
viewed by particular users.";
}
typedef stat-interval {
type uint64;
units nanoseconds;
description
"A time interval over which a set of statistics is computed.
A common usage is to report the interval over which
avg/min/max stats are computed and reported.";
}
grouping stat-interval-state {
description
"Reusable leaf definition for stats computation interval";
leaf interval {
type oc-types:stat-interval;
description
"If supported by the system, this reports the time interval
over which the min/max/average statistics are computed by
the system.";
}
}
grouping min-max-time {
description
"Common grouping for recording the absolute time at which
the minimum and maximum values occurred in the statistics";
leaf min-time {
type oc-types:timeticks64;
description
"The absolute time at which the minimum value occurred.
The value is the timestamp in nanoseconds relative to
the Unix Epoch (Jan 1, 1970 00:00:00 UTC).";
}
leaf max-time {
type oc-types:timeticks64;
description
"The absolute time at which the maximum value occurred.
The value is the timestamp in nanoseconds relative to
the Unix Epoch (Jan 1, 1970 00:00:00 UTC).";
}
}
grouping avg-min-max-stats-precision1 {
description
"Common nodes for recording average, minimum, and
maximum values for a statistic. These values all have
fraction-digits set to 1. Statistics are computed
and reported based on a moving time interval (e.g., the last
30s). If supported by the device, the time interval over which
the statistics are computed is also reported.";
leaf avg {
type decimal64 {
fraction-digits 1;
}
description
"The arithmetic mean value of the statistic over the
time interval.";
}
leaf min {
type decimal64 {
fraction-digits 1;
}
description
"The minimum value of the statistic over the time
interval.";
}
leaf max {
type decimal64 {
fraction-digits 1;
}
description
"The maximum value of the statitic over the time
interval.";
}
uses stat-interval-state;
uses min-max-time;
}
grouping avg-min-max-instant-stats-precision1 {
description
"Common grouping for recording an instantaneous statistic value
in addition to avg-min-max stats";
leaf instant {
type decimal64 {
fraction-digits 1;
}
description
"The instantaneous value of the statistic.";
}
uses avg-min-max-stats-precision1;
}
grouping avg-min-max-instant-stats-precision2-dB {
description
"Common grouping for recording dB values with 2 decimal
precision. Values include the instantaneous, average,
minimum, and maximum statistics. Statistics are computed
and reported based on a moving time interval (e.g., the last
30s). If supported by the device, the time interval over which
the statistics are computed, and the times at which the minimum
and maximum values occurred, are also reported.";
leaf instant {
type decimal64 {
fraction-digits 2;
}
units dB;
description
"The instantaneous value of the statistic.";
}
leaf avg {
type decimal64 {
fraction-digits 2;
}
units dB;
description
"The arithmetic mean value of the statistic over the
time interval.";
}
leaf min {
type decimal64 {
fraction-digits 2;
}
units dB;
description
"The minimum value of the statistic over the time interval.";
}
leaf max {
type decimal64 {
fraction-digits 2;
}
units dB;
description
"The maximum value of the statistic over the time
interval.";
}
uses stat-interval-state;
uses min-max-time;
}
grouping avg-min-max-instant-stats-precision2-dBm {
description
"Common grouping for recording dBm values with 2 decimal
precision. Values include the instantaneous, average,
minimum, and maximum statistics. Statistics are computed
and reported based on a moving time interval (e.g., the last
30s). If supported by the device, the time interval over which
the statistics are computed, and the times at which the minimum
and maximum values occurred, are also reported.";
leaf instant {
type decimal64 {
fraction-digits 2;
}
units dBm;
description
"The instantaneous value of the statistic.";
}
leaf avg {
type decimal64 {
fraction-digits 2;
}
units dBm;
description
"The arithmetic mean value of the statistic over the
time interval.";
}
leaf min {
type decimal64 {
fraction-digits 2;
}
units dBm;
description
"The minimum value of the statistic over the time
interval.";
}
leaf max {
type decimal64 {
fraction-digits 2;
}
units dBm;
description
"The maximum value of the statistic over the time interval.";
}
uses stat-interval-state;
uses min-max-time;
}
grouping avg-min-max-instant-stats-precision2-mA {
description
"Common grouping for recording mA values with 2 decimal
precision. Values include the instantaneous, average,
minimum, and maximum statistics. Statistics are computed
and reported based on a moving time interval (e.g., the last
30s). If supported by the device, the time interval over which
the statistics are computed, and the times at which the minimum
and maximum values occurred, are also reported.";
leaf instant {
type decimal64 {
fraction-digits 2;
}
units mA;
description
"The instantaneous value of the statistic.";
}
leaf avg {
type decimal64 {
fraction-digits 2;
}
units mA;
description
"The arithmetic mean value of the statistic over the
time interval.";
}
leaf min {
type decimal64 {
fraction-digits 2;
}
units mA;
description
"The minimum value of the statistic over the time
interval.";
}
leaf max {
type decimal64 {
fraction-digits 2;
}
units mA;
description
"The maximum value of the statistic over the time
interval.";
}
uses stat-interval-state;
uses min-max-time;
}
grouping avg-min-max-instant-stats-pct {
description
"Common grouping for percentage statistics.
Values include the instantaneous, average,
minimum, and maximum statistics. Statistics are computed
and reported based on a moving time interval (e.g., the last
30s). If supported by the device, the time interval over which
the statistics are computed, and the times at which the minimum
and maximum values occurred, are also reported.";
leaf instant {
type oc-types:percentage;
description
"The instantaneous percentage value.";
}
leaf avg {
type oc-types:percentage;
description
"The arithmetic mean value of the percentage measure of the
statistic over the time interval.";
}
leaf min {
type oc-types:percentage;
description
"The minimum value of the percentage measure of the
statistic over the time interval.";
}
leaf max {
type oc-types:percentage;
description
"The maximum value of the percentage measure of the
statistic over the time interval.";
}
uses stat-interval-state;
uses min-max-time;
}
identity ADDRESS_FAMILY {
description
"A base identity for all address families";
}
identity IPV4 {
base ADDRESS_FAMILY;
description
"The IPv4 address family";
}
identity IPV6 {
base ADDRESS_FAMILY;
description
"The IPv6 address family";
}
identity MPLS {
base ADDRESS_FAMILY;
description
"The MPLS address family";
}
identity L2_ETHERNET {
base ADDRESS_FAMILY;
description
"The 802.3 Ethernet address family";
}
}

View File

@@ -0,0 +1,250 @@
module openconfig-yang-types {
yang-version "1";
namespace "http://openconfig.net/yang/types/yang";
prefix "oc-yang";
import openconfig-extensions { prefix "oc-ext"; }
organization
"OpenConfig working group";
contact
"OpenConfig working group
www.openconfig.net";
description
"This module contains a set of extension types to the
YANG builtin types that are used across multiple
OpenConfig models.
Portions of this code were derived from IETF RFC 6021.
Please reproduce this note if possible.
IETF code is subject to the following copyright and license:
Copyright (c) IETF Trust and the persons identified as authors of
the code.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, is permitted pursuant to, and subject to the license
terms contained in, the Simplified BSD License set forth in
Section 4.c of the IETF Trust's Legal Provisions Relating
to IETF Documents (http://trustee.ietf.org/license-info).";
oc-ext:openconfig-version "1.0.0";
revision "2024-05-30" {
description
"Add hex-string-prefixed typedef";
reference "1.0.0";
}
revision "2021-07-14" {
description
"Use auto-generated regex for certain pattern statements:
- dotted-quad
- date-and-time
- date
For date-and-time, allow lowercase z and t in the pattern.";
reference "0.3.1";
}
revision "2021-03-02" {
description
"Fix date-and-time and date's pattern statement, and remove the
regexp-posix extension, which makes pattern statements conform to the
YANG standard.";
reference "0.3.0";
}
revision "2020-06-30" {
description
"Add OpenConfig POSIX pattern extensions.";
reference "0.2.2";
}
revision "2018-11-21" {
description
"Add OpenConfig module metadata extensions.";
reference "0.2.1";
}
revision 2018-04-24 {
description
"Add date typedef";
reference "0.2.0";
}
revision 2017-07-30 {
description
"Fixed unprintable character";
reference "0.1.2";
}
revision 2017-04-03 {
description
"Update copyright notice.";
reference "0.1.1";
}
revision 2017-01-26 {
description
"Initial module for inet types";
reference "0.1.0";
}
// OpenConfig specific extensions for module metadata.
oc-ext:catalog-organization "openconfig";
oc-ext:origin "openconfig";
typedef dotted-quad {
type string {
pattern
'([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]|'
+ '[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}';
oc-ext:posix-pattern
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]|'
+ '[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3})$';
}
description
"An unsigned 32-bit integer expressed as a dotted quad. The
format is four octets written as decimal numbers separated
with a period character.";
}
typedef hex-string {
status deprecated;
type string {
pattern '[0-9a-fA-F]*';
oc-ext:posix-pattern '^[0-9a-fA-F]*$';
}
description
"A string consisting of a hexadecimal characters. This leaf is
deprecated and will removed in a future version of this model.
The type hex-string-prefixed should be used instead.";
}
typedef hex-string-prefixed {
type string {
pattern '(0x)([0-9a-fA-F]{2})*';
oc-ext:posix-pattern '^(0x)([0-9a-fA-F]{2})*$';
length "3..max";
}
description
"A string encoding a hexadecimal number with a prefix of '0x' followed
by a list of bytes.";
}
typedef counter32 {
type uint32;
description
"A 32-bit counter. A counter value is a monotonically increasing
value which is used to express a count of a number of
occurrences of a particular event or entity. When the counter
reaches its maximum value, in this case 2^32-1, it wraps to 0.
Discontinuities in the counter are generally triggered only when
the counter is reset to zero.";
}
typedef counter64 {
type uint64;
description
"A 64-bit counter. A counter value is a monotonically increasing
value which is used to express a count of a number of
occurrences of a particular event or entity. When a counter64
reaches its maximum value, 2^64-1, it loops to zero.
Discontinuities in a counter are generally triggered only when
the counter is reset to zero, through operator or system
intervention.";
}
typedef date-and-time {
type string {
pattern
'[0-9]{4}\-(0[1-9]|1[0-2])\-(0[1-9]|[12][0-9]|3[01])[Tt](0[0-9]|'
+ '1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9]):(0[0-9]|[1-5][0-9]|'
+ '60)(\.[0-9]+)?([Zz]|([+-](0[0-9]|1[0-9]|2[0-3]):(0[0-9]|'
+ '[1-5][0-9])))';
oc-ext:posix-pattern
'^([0-9]{4}\-(0[1-9]|1[0-2])\-(0[1-9]|[12][0-9]|3[01])[Tt](0[0-9]|'
+ '1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9]):(0[0-9]|[1-5][0-9]|'
+ '60)(\.[0-9]+)?([Zz]|([+-](0[0-9]|1[0-9]|2[0-3]):(0[0-9]|'
+ '[1-5][0-9]))))$';
}
description
"A date and time, expressed in the format described in RFC3339.
That is to say:
YYYY-MM-DDTHH:MM:SSZ+-hh:mm
where YYYY is the year, MM is the month expressed as a two-digit
month (zero padding if required), DD is the day of the month,
expressed as a two digit value. T is the literal character 'T',
HH is the hour of the day expressed as a two digit number, using
the 24-hour clock, MM is the minute of the hour expressed as a
two digit number. Z is the literal character 'Z', followed by a
timezone offset expressed in hours (hh) and minutes (mm), both
expressed as two digit numbers. The time offset is specified as
a positive or negative offset to UTC using the '+' or '-'
character preceding the offset.
Optionally, fractional seconds can be expressed after the minute
of the hour as a decimal number of unspecified precision
reflecting fractions of a second.";
reference
"RFC3339 - Date and Time on the Internet: Timestamps";
}
typedef date {
type string {
pattern
'[0-9]{4}\-(0[1-9]|1[0-2])\-(0[1-9]|[12][0-9]|3[01])';
oc-ext:posix-pattern
'^([0-9]{4}\-(0[1-9]|1[0-2])\-(0[1-9]|[12][0-9]|3[01]))$';
}
description
"A full UTC date, expressed in the format described in RFC3339.
That is to say:
YYYY-MM-DD
where YYYY is the year, MM is the month expressed as a two-digit
month (zero padding if required), DD is the day of the month,
expressed as a two digit value.";
reference
"RFC3339 - Date and Time on the Internet: full-date";
}
typedef gauge64 {
type uint64;
description
"A gauge value may increase or decrease - and reflects a value
at a particular point in time. If the value of the variable
being modeled using the gauge exceeds its maximum - 2^64-1 in
this case - the gauge is set to its maximum value.";
}
typedef phys-address {
type string {
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
oc-ext:posix-pattern '^([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?$';
}
description
"A physical layer address, expressed as a series of pairs of
hexadecimal digits.";
}
typedef mac-address {
type string {
pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
oc-ext:posix-pattern '^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}$';
}
description
"An IEEE 802 MAC address";
}
}

View File

@@ -0,0 +1,214 @@
import json
import re
import pandas as pd
import ipaddress
import time
from collections import deque
from openpyxl import load_workbook
from scripts.style_excel.style_address_groups import style_address_groups
from scripts.style_excel.style_service_groups import style_service_groups
from scripts.style_excel.style_matrice_flux import style_matrice_flux
def export_to_excel(json_file_path, output_file_excel):
"""
Export firewall data from JSON to Excel
Args:
json_file_path: Path to the JSON file to process
output_file_excel: Path to the output Excel file
"""
# === Load JSON ===
with open(json_file_path, "r", encoding="utf-8") as f:
data = json.load(f)
acls = data.get("openconfig-acl:acl", {}).get("acl-sets", {}).get("acl-set", [])
objects = data.get("custom-firewall-objects:firewall-objects", {})
addresses = {a["name"]: a["config"] for a in objects.get("address", [])}
address_groups = {g["name"]: g["config"] for g in objects.get("address-group", [])}
services = {s["name"]: s["config"] for s in objects.get("service", [])}
service_groups = {g["name"]: g["config"] for g in objects.get("service-group", [])}
# === Load site mapping ===
with open("src/data/site.json", "r", encoding="utf-8") as f:
site_mapping = json.load(f)
# === Build flow matrix helpers ===
def get_tier_from_tags(tags):
s = ""
for t in ["T0","T1A","T1B","T2A","T2B"]:
if any(t in str(tag) for tag in tags): s += t + ","
return s[:-1] if s else ""
# === Extract tags without tier info ===
def get_tags_without_tier(text):
if not text: return ""
tags = re.findall(r"Misc\s*:\s*(.*)", text)
if not tags: return ""
tag_list = [tag.strip() for tag in tags[0].split(",")]
filtered_tags = [tag for tag in tag_list if tag not in ["T0","T1A","T1B","T2A","T2B"]]
return ", ".join(filtered_tags)
# === Resolve equipment to members ===
def resolve_equipment(name):
if str(name).lower() == "any": return ["any"]
if name in address_groups: return address_groups[name].get("members", [])
return [name]
# === Resolve equipment to IP/mask ===
def resolve_ip_masks(equipment_list):
if not equipment_list:
return ""
clean = str(equipment_list).replace("[","").replace("]","").replace("'","").replace('"',"")
eq_list = [eq.strip() for eq in clean.split(",") if eq.strip()]
cidrs = []
for eq in eq_list:
if eq in addresses:
ip = addresses[eq].get("ip_netmask","")
if ip:
cidrs.append(ip if "/" in ip else ip+"/32")
return ", ".join(cidrs)
# === Recursive address resolver ===
def resolve_all_addresses(equipment_list):
resolved = set()
eq_list = []
for item in equipment_list:
if isinstance(item, str):
if ',' in item:
eq_list.extend([eq.strip() for eq in item.split(',') if eq.strip()])
else:
eq_list.append(item.strip())
else:
eq_list.append(item)
to_process = deque(eq_list)
processed = set()
while to_process:
eq = to_process.popleft()
if eq in processed: continue
processed.add(eq)
if eq in addresses:
resolved.add(eq)
elif eq in address_groups:
members = address_groups[eq].get("members", [])
new_members = [m for m in members if m not in processed]
to_process.extend(new_members)
return list(resolved)
# === Map addresses to sites ===
def get_sites_for_addresses(address_list):
sites = set()
for addr in address_list:
ipmask = addresses.get(addr, {}).get("ip_netmask", "")
if not ipmask:
continue
ipmask = ipmask if "/" in ipmask else ipmask + "/32"
# cas particulier d'une plage d'IP format "CIDR1-CIDR2"
if "-" in ipmask:
start_ip, end_ip = ipmask.split("-")
end_ip = end_ip.split("/")[0]
for ip in range(int(ipaddress.ip_address(start_ip)), int(ipaddress.ip_address(end_ip)) + 1):
ip_obj = ipaddress.ip_network(f"{ipaddress.ip_address(ip)}/32", strict=False)
for cidr, site in site_mapping.items():
site_cidr = ipaddress.ip_network(cidr, strict=False)
if ip_obj.network_address in site_cidr or ip_obj.subnet_of(site_cidr):
sites.add(site)
break
continue
ip_obj = ipaddress.ip_network(ipmask, strict=False)
for cidr, site in site_mapping.items():
site_cidr = ipaddress.ip_network(cidr, strict=False)
if ip_obj.network_address in site_cidr or ip_obj.subnet_of(site_cidr):
sites.add(site)
break
return ", ".join(sorted(sites))
rows=[]
for acl in acls:
acl_name = acl.get("name","")
acl_desc = acl.get("config",{}).get("description","")
enabled = acl.get("state",{}).get("description","")
for entry in acl.get("acl-entries",{}).get("acl-entry",[]):
cfg = entry.get("config",{})
ipv4 = entry.get("ipv4",{}).get("config",{})
transport = entry.get("transport",{}).get("config",{})
actions = entry.get("actions",{}).get("config",{})
state = entry.get("state",{})
src_name = ipv4.get("source-address","any")
src_e = resolve_equipment(src_name)
src_c = resolve_ip_masks(src_e)
dst_name = ipv4.get("destination-address","any")
dst_e = resolve_equipment(dst_name)
dst_c = resolve_ip_masks(dst_e)
src_sites = get_sites_for_addresses(resolve_all_addresses(src_e))
dst_sites = get_sites_for_addresses(resolve_all_addresses(dst_e))
rows.append({
"Nom du flux": acl_name,
"Description": acl_desc,
"Src Equipement": ", ".join(src_e),
"Src CIDR": src_c,
"Src VLAN":"",
"Src Site": src_sites,
"Dst Equipement": ", ".join(dst_e),
"Dst CIDR": dst_c,
"Dst VLAN":"",
"Dst Site": dst_sites,
"Application": cfg.get("description",""),
"Port": transport.get("destination-port",""),
"Miscellaneous": get_tags_without_tier(state.get("description","")),
"Action": actions.get("forwarding-action","").replace("openconfig-acl:",""),
"Tier": get_tier_from_tags([state.get("description","")]),
"Active": "Oui" if enabled is True else "Non"
})
df = pd.DataFrame(rows)
df_addr = pd.DataFrame([
{
"Group Name": g,
"Member": m,
"IP": addresses[m]["ip_netmask"] if m in addresses and "/" in addresses[m].get("ip_netmask","") else
(addresses[m]["ip_netmask"]+"/32" if m in addresses else "")
}
for g, cfg in address_groups.items()
for m in cfg.get("members", [])
])
df_srv = pd.DataFrame([
{
"Group Name": g,
"Member": m,
"Protocol": services[m]["protocol"] if m in services and "protocol" in services[m] else "",
"Port": services[m]["port"] if m in services and "port" in services[m] else ""
}
for g, cfg in service_groups.items()
for m in cfg.get("members", [])
])
# === Export Excel ===
firewall_type = data.get("firewall-device", {}).get("type", "firewall").replace(" ","_").lower()
date = time.strftime("%Y%m%d")
with pd.ExcelWriter(output_file_excel, engine="openpyxl") as writer:
df_addr.to_excel(writer,sheet_name="Address-Groups",index=False)
df_srv.to_excel(writer,sheet_name="Service-Groups",index=False)
df.to_excel(writer,sheet_name="Matrice Flux",index=False,startrow=1)
wb = load_workbook(output_file_excel)
if "Sheet1" in wb.sheetnames:
del wb["Sheet1"]
style_address_groups(wb["Address-Groups"], address_groups)
style_service_groups(wb["Service-Groups"], service_groups)
style_matrice_flux(wb["Matrice Flux"])
wb.save(output_file_excel)
print(f"✓ Export Excel OK: {output_file_excel}")
return output_file_excel

View File

@@ -0,0 +1,296 @@
#!/usr/bin/env python3
"""
Modèle de base pour les parsers de configurations de firewalls vers un format json normalisé OpenConfig YANG
Fournit des méthodes communes pour la conversion et l'exportation des données
"""
from typing import Dict, Any
class ParserMixin:
def to_openconfig_yang(self, type) -> Dict[str, Any]:
"""Convertit la configuration au format OpenConfig YANG avec les nouveaux modèles"""
openconfig = {
"firewall-device": {
"type": type
},
"openconfig-interfaces:interfaces": {
"interface": []
},
"openconfig-network-instance:network-instances": {
"network-instance": []
},
"openconfig-acl:acl": {
"acl-sets": {
"acl-set": []
}
},
"custom-firewall-objects:firewall-objects": {
"address": [],
"address-group": [],
"service": [],
"service-group": []
}
}
# Conversion des interfaces
for interface in self.config['interfaces']:
intf_config = {
"name": interface.name,
"config": {
"name": interface.name,
"type": "iana-if-type:ethernetCsmacd" if interface.interface_type == "ethernet" else "iana-if-type:ieee8023adLag",
"enabled": interface.enabled,
"description": interface.comment or ""
}
}
if interface.ip:
intf_config["subinterfaces"] = {
"subinterface": [
{
"index": interface.misc or 0,
"config": {
"index": interface.misc or 0,
"enabled": interface.enabled
},
"oc-ip:ipv4": {
"oc-ip:addresses": {
"oc-ip:address": [
{
"oc-ip:ip": interface.ip,
"oc-ip:config": {
"oc-ip:ip": interface.ip,
"oc-ip:prefix-length": interface.netmask if interface.netmask else 24
}
}
]
}
}
}
]
}
openconfig["openconfig-interfaces:interfaces"]["interface"].append(intf_config)
# Conversion des virtual-routers et routes statiques
for vr in self.config.get('virtual_routers', []):
vr_entry = {
"name": vr.name,
"config": {
"name": vr.name,
"type": "L3VRF"
},
"interfaces": {
"interface": [{"id": iface} for iface in vr.interfaces]
},
"protocols": {
"protocol": [
{
"identifier": "STATIC",
"name": "STATIC",
"static-routes": {
"static": []
}
}
]
}
}
static_list = vr_entry["protocols"]["protocol"][0]["static-routes"]["static"]
for route in vr.static_routes:
prefix = route.destination
next_hops = []
nh_config = {
"index": route.name,
"config": {
"index": route.name,
"next-hop": route.next_vr if route.next_vr else route.next_hop_ip,
"metric": route.metric if getattr(route, "metric", None) is not None else 0
}
}
if route.next_vr:
nh_config["config"]["oc-loc-rt-netinst:next-network-instance"] = route.next_vr
nh_config["config"]["oc-loc-rt-netinst:nh-network-instance"] = None
elif route.next_hop_ip:
nh_config["config"]["oc-loc-rt-netinst:next-network-instance"] = None
nh_config["config"]["oc-loc-rt-netinst:nh-network-instance"] = vr.name
if route.interface:
nh_config["interface-ref"] = {
"config": {
"interface": route.interface,
}
}
next_hops.append(nh_config)
static_entry = {
"prefix": prefix,
"next-hops": {
"next-hop": next_hops
}
}
static_list.append(static_entry)
openconfig["openconfig-network-instance:network-instances"]["network-instance"].append(vr_entry)
# Conversion des règles de sécurité en ACL
for rule in self.config['security_rules']:
acl_entry = {
"name": rule.name,
"type": "openconfig-acl:ACL_IPV4",
"config": {
"name": rule.name,
"type": "openconfig-acl:ACL_IPV4",
"description": getattr(rule, 'description', "")
},
"state": {
"description": getattr(rule, 'enabled', "")
},
"acl-entries": {
"acl-entry": []
}
}
if getattr(rule, "action", "").lower() == "nat":
action_base = "openconfig-acl:NAT"
else:
action_base = (
"openconfig-acl:ACCEPT" if getattr(rule, "action", "").lower() == "allow"
else "openconfig-acl:DROP"
)
if hasattr(rule, "enabled") and not rule.enabled:
action_value = f"{action_base}_DISABLED"
else:
action_value = action_base
miscs_text = (
f"Misc: {', '.join(rule.miscs)}"
if hasattr(rule, "miscs") and rule.miscs
else ""
)
ports = []
for s in getattr(rule, "services", []):
if s.lower().startswith("port"):
ports.append(s[4:])
else:
ports.append(s)
desc_parts = []
if getattr(rule, "action", "").lower() == "nat":
if getattr(rule, "to_interface", ""):
desc_parts.append(rule.to_interface)
if getattr(rule, "translated_address", ""):
desc_parts.append(rule.translated_address)
if getattr(rule, "translated_port", ""):
desc_parts.append(rule.translated_port)
entry = {
"sequence-id": getattr(rule, "sequence_id", 1),
"config": {
"sequence-id": getattr(rule, "sequence_id", 1),
"description": desc_parts if desc_parts else getattr(rule, "applications", "")
},
"state": {
"sequence-id": getattr(rule, "sequence_id", 1),
"description": miscs_text
},
"ipv4": {
"config": {
"source-address": ",".join(rule.source_addresses) if hasattr(rule, "source_addresses") else "any",
"destination-address": ",".join(rule.destination_addresses) if hasattr(rule, "destination_addresses") else "any",
# "source-address-prefix-set": ",".join(rule.from_zones) if hasattr(rule, "from_zones") else "",
# "destination-address-prefix-set": ",".join(rule.to_zones) if hasattr(rule, "to_zones") else ""
}
},
"transport": {
"config": {
"source-port": "any",
"destination-port": ",".join(ports) if ports else "any",
}
},
"actions": {
"config": {
"forwarding-action": action_value,
"log-action": getattr(rule, "log_setting", "default")
}
}
}
acl_entry["acl-entries"]["acl-entry"].append(entry)
openconfig["openconfig-acl:acl"]["acl-sets"]["acl-set"].append(acl_entry)
# Conversion des objets firewall personnalisés
# Address objects
for addr_obj in self.config['address_objects']:
address_config = {
"name": addr_obj.name,
"config": {
"name": addr_obj.name,
"ip_netmask": addr_obj.ip_netmask,
"description": addr_obj.description,
"misc": addr_obj.misc
}
}
openconfig["custom-firewall-objects:firewall-objects"]["address"].append(address_config)
# Address groups
for addr_group in self.config['address_groups']:
address_group_config = {
"name": addr_group.name,
"config": {
"name": addr_group.name,
"members": addr_group.members,
"description": addr_group.description,
"misc": addr_group.misc
}
}
openconfig["custom-firewall-objects:firewall-objects"]["address-group"].append(address_group_config)
# Service objects
for svc_obj in self.config['service_objects']:
service_config = {
"name": svc_obj.name,
"config": {
"name": svc_obj.name,
"protocol": svc_obj.protocol,
"port": svc_obj.port,
"source_port": svc_obj.source_port,
"description": svc_obj.description,
"misc": svc_obj.misc
}
}
openconfig["custom-firewall-objects:firewall-objects"]["service"].append(service_config)
# Service groups
for svc_group in self.config['service_groups']:
service_group_config = {
"name": svc_group.name,
"config": {
"name": svc_group.name,
"members": svc_group.members,
"description": svc_group.description,
"misc": svc_group.misc
}
}
openconfig["custom-firewall-objects:firewall-objects"]["service-group"].append(service_group_config)
return openconfig
def print_summary(self):
"""Affiche un résumé de la configuration parsée"""
print("\n" + "="*50)
print("RÉSUMÉ DE LA CONFIGURATION")
print("="*50)
print(f"Objets adresse: {len(self.config['address_objects'])}")
print(f"Groupes d'adresses: {len(self.config['address_groups'])}")
print(f"Objets service: {len(self.config['service_objects'])}")
print(f"Groupes de services: {len(self.config['service_groups'])}")
print(f"Interfaces: {len(self.config['interfaces'])}")
print(f"Règles de sécurité: {len(self.config['security_rules'])}")

View File

@@ -0,0 +1,215 @@
#!/usr/bin/env python3
"""
Parser pour configuration Forcepoint XML vers un format json normalisé OpenConfig YANG
Extrait les groupes d'objets, objets, groupes de services, services, routes, interfaces et règles
"""
import xml.etree.ElementTree as ET
import json
from scripts.export_modele import ParserMixin
from scripts.objets.data import AddressObject, AddressGroup, ServiceObject, ServiceGroup, Interface, SecurityRule, StaticRoute, VirtualRouter
from pathlib import Path
class ForcepointParser(ParserMixin):
"""Parser pour fichier XML Forcepoint"""
def __init__(self, xml_file_path: str):
"""Initialise le parser avec le chemin du fichier XML"""
self.xml_file = xml_file_path
self.tree = None
self.root = None
self.config = {
'address_objects': [],
'address_groups': [],
'service_objects': [],
'service_groups': [],
'interfaces': [],
'virtual_routers': [],
'static_routes': [],
'security_rules': []
}
def load_xml(self):
"""Charge le fichier XML"""
try:
self.tree = ET.parse(self.xml_file)
self.root = self.tree.getroot()
print(f"✓ Fichier XML chargé: {self.xml_file}")
except ET.ParseError as e:
print(f"✗ Erreur de parsing XML: {e}")
raise
except FileNotFoundError:
print(f"✗ Fichier non trouvé: {self.xml_file}")
raise
def _parse_address_objects(self):
"""Parse hosts, networks, address ranges et ip_lists"""
for obj in self.root.findall(".//host"):
name = obj.get("name")
ip = obj.find("mvia_address")
ip_addr = ip.get("address") if ip is not None else None
desc = obj.get("comment") or None
self.config['address_objects'].append(AddressObject(name=name, ip_netmask=ip_addr, description=desc))
for obj in self.root.findall(".//network"):
name = obj.get("name")
ip_netmask = obj.get("ipv4_network")
comment = obj.get("comment")
self.config['address_objects'].append(AddressObject(name=name, ip_netmask=ip_netmask, description=comment))
for obj in self.root.findall(".//address_range"):
name = obj.get("name")
ip_range = obj.get("ip_range")
comment = obj.get("comment")
self.config['address_objects'].append(AddressObject(name=name, ip_netmask=ip_range, description=comment))
for obj in self.root.findall(".//ip_list"):
name = obj.get("name")
ips = [ip.get("value") for ip in obj.findall(".//ip")]
for ip in ips:
self.config['address_objects'].append(AddressObject(name=f"{name}_{ip}", ip_netmask=ip))
def _parse_address_groups(self):
"""Parse les groupes d'adresses"""
for group in self.root.findall(".//group"):
name = group.get("name")
desc = group.get("comment") or None
members = [m.get("ref") for m in group.findall(".//ne_list")]
self.config['address_groups'].append(AddressGroup(name=name, members=members, description=desc))
def _parse_service_objects(self):
"""Parse services TCP/UDP"""
for svc in self.root.findall(".//service_tcp"):
name = svc.get("name")
port = svc.get("min_dst_port")
proto = "tcp"
self.config['service_objects'].append(ServiceObject(name=name, protocol=proto, port=port))
for svc in self.root.findall(".//service_udp"):
name = svc.get("name")
port = svc.get("min_dst_port")
proto = "udp"
self.config['service_objects'].append(ServiceObject(name=name, protocol=proto, port=port))
def _parse_interfaces(self):
"""Parse interfaces de cluster"""
for iface in self.root.findall(".//cluster_virtual_interface"):
name = iface.get("name")
iptmp = iface.find("mvia_address")
ip_addr = iptmp.get("address") if iptmp is not None else None
net = iface.get("network_value")
netmask = net.split("/")[-1] if net else None
comment = iface.get("comment")
self.config['interfaces'].append(Interface(name=name, ip=ip_addr, netmask=netmask, comment=comment))
def _parse_virtual_routers(self):
"""Parse routeurs simples"""
for router in self.root.findall(".//router"):
name = router.get("name")
ip = router.find("mvia_address")
ip_addr = ip.get("address") if ip is not None else None
self.config['virtual_routers'].append(VirtualRouter(name=name, interfaces=[ip_addr] if ip_addr else [], static_routes=[]))
def _parse_security_rules(self):
"""Parse règles FW Forcepoint"""
for rule_entry in self.root.findall(".//fw_policy//rule_entry"):
rule_type = rule_entry.find("./access_rule") or rule_entry.find("./nat_rule")
if rule_type is None:
continue
name = rule_entry.get("tag")
action = rule_type.find("./action")
action_type = action.get("type") if action is not None else "undefined"
sources = [s.get("value") for s in rule_type.findall(".//match_sources//match_source_ref")]
destinations = [d.get("value") for d in rule_type.findall(".//match_destinations//match_destination_ref")]
services = [s.get("value") for s in rule_type.findall(".//match_services//match_service_ref")]
enabled_attr = rule_entry.get("is_disabled")
enabled = False if enabled_attr == "true" else True
desc = rule_entry.get("comment") or None
self.config['security_rules'].append(
SecurityRule(
name=f"Rule_{name}",
source_addresses=sources,
destination_addresses=destinations,
services=services,
action=action_type,
from_zones=[],
to_zones=[],
applications=[],
description=desc,
enabled=enabled
)
)
def parse_all(self):
"""Parse tous les éléments de configuration"""
print("Début du parsing de la configuration Forcepoint...")
self.load_xml()
self._parse_address_objects()
self._parse_address_groups()
self._parse_service_objects()
self._parse_interfaces()
self._parse_virtual_routers()
self._parse_security_rules()
print("✓ Parsing terminé avec succès!")
def export_to_json(self, output_file: str):
"""Exporte la configuration au format JSON OpenConfig"""
openconfig_data = self.to_openconfig_yang("forcepoint")
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(openconfig_data, f, indent=2, ensure_ascii=False)
print(f"✓ Configuration exportée vers: {output_file}")
def generate_json_forcepoint(input_file: str, output_file: str):
"""Génère le fichier JSON OpenConfig à partir du fichier XML Forcepoint"""
xml_file = Path(input_file)
if not xml_file.exists():
print(f"✗ Erreur: Le fichier '{xml_file}' n'existe pas")
return
try:
parser = ForcepointParser(str(xml_file))
parser.parse_all()
parser.print_summary()
output_file = output_file
parser.export_to_json(output_file)
print(f"\n✓ Conversion terminée! Vérifiez le fichier: {output_file}")
except Exception as e:
print(f"✗ Erreur: {e}")
return
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print("Usage: python json_Forcepoint.py <fichier_config.xml>")
print("Exemple: python json_Forcepoint.py config_Forcepoint.xml")
sys.exit(1)
xml_file = sys.argv[1]
if not Path(xml_file).exists():
print(f"✗ Erreur: Le fichier '{xml_file}' n'existe pas")
sys.exit(1)
try:
parser = ForcepointParser(xml_file)
parser.parse_all()
parser.print_summary()
input_path = Path(xml_file)
output_file = 'output_Forcepoint.json'
parser.export_to_json(output_file)
print(f"\n✓ Conversion terminée! Vérifiez le fichier: {output_file}")
except Exception as e:
print(f"✗ Erreur: {e}")
sys.exit(1)

View File

@@ -0,0 +1,508 @@
#!/usr/bin/env python3
"""
Parser pour configuration Palo Alto XML vers un format json normalisé OpenConfig YANG
Extrait les groupes d'objets, objets, groupes de services, services, routes, interfaces et règles
"""
import xml.etree.ElementTree as ET
import json
from scripts.export_modele import ParserMixin
from scripts.objets.data import AddressObject, AddressGroup, ServiceObject, ServiceGroup, Interface, SecurityRule, StaticRoute, VirtualRouter
from pathlib import Path
class PaloAltoParser(ParserMixin):
"""Parser pour fichier XML Palo Alto"""
def __init__(self, xml_file_path: str):
"""Initialise le parser avec le chemin du fichier XML"""
self.xml_file = xml_file_path
self.tree = None
self.root = None
self.config = {
'address_objects': [],
'address_groups': [],
'service_objects': [],
'service_groups': [],
'interfaces': [],
'virtual_routers': [],
'static_routes': [],
'security_rules': []
}
def load_xml(self):
"""Charge le fichier XML"""
try:
self.tree = ET.parse(self.xml_file)
self.root = self.tree.getroot()
print(f"✓ Fichier XML chargé: {self.xml_file}")
except ET.ParseError as e:
print(f"✗ Erreur de parsing XML: {e}")
raise
except FileNotFoundError:
print(f"✗ Fichier non trouvé: {self.xml_file}")
raise
def _parse_address_objects(self):
"""Parse les objets adresse"""
address_objects = []
paths = [
".//shared/address/entry",
".//devices/entry/vsys/entry/address/entry"
]
for path in paths:
for addr in self.root.findall(path):
name = addr.get('name')
obj = AddressObject(name=name)
# IP/Netmask
ip_netmask = addr.find('ip-netmask')
if ip_netmask is not None:
obj.ip_netmask = ip_netmask.text
# Description
desc = addr.find('description')
if desc is not None:
obj.description = desc.text
# Misc
misc_elem = addr.find('tag')
if misc_elem is not None:
for member in misc_elem.findall('member'):
obj.misc.append(member.text)
address_objects.append(obj)
self.config['address_objects'] = address_objects
print(f"✓ Trouvé {len(address_objects)} objets adresse")
def _parse_address_groups(self):
"""Parse les groupes d'adresses"""
address_groups = []
paths = [
".//shared/address-group/entry",
".//devices/entry/vsys/entry/address-group/entry"
]
for path in paths:
for group in self.root.findall(path):
name = group.get('name')
members = []
# Membres statiques
static = group.find('static')
if static is not None:
for member in static.findall('member'):
members.append(member.text)
obj = AddressGroup(name=name, members=members)
# Description
desc = group.find('description')
if desc is not None:
obj.description = desc.text
# Misc
misc_elem = group.find('tag')
if misc_elem is not None:
for member in misc_elem.findall('member'):
obj.misc.append(member.text)
address_groups.append(obj)
self.config['address_groups'] = address_groups
print(f"✓ Trouvé {len(address_groups)} groupes d'adresses")
def _parse_service_objects(self):
"""Parse les objets service"""
service_objects = []
paths = [
".//shared/service/entry",
".//devices/entry/vsys/entry/service/entry"
]
for path in paths:
for service in self.root.findall(path):
name = service.get('name')
obj = ServiceObject(name=name)
# Protocol TCP
tcp = service.find('protocol/tcp')
if tcp is not None:
obj.protocol = 'tcp'
port = tcp.find('port')
if port is not None:
obj.port = port.text
source_port = tcp.find('source-port')
if source_port is not None:
obj.source_port = source_port.text
# Protocol UDP
udp = service.find('protocol/udp')
if udp is not None:
obj.protocol = 'udp'
port = udp.find('port')
if port is not None:
obj.port = port.text
source_port = udp.find('source-port')
if source_port is not None:
obj.source_port = source_port.text
# Description
desc = service.find('description')
if desc is not None:
obj.description = desc.text
# Misc
misc_elem = service.find('tag')
if misc_elem is not None:
for member in misc_elem.findall('member'):
obj.misc.append(member.text)
service_objects.append(obj)
self.config['service_objects'] = service_objects
print(f"✓ Trouvé {len(service_objects)} objets service")
def _parse_service_groups(self):
"""Parse les groupes de services"""
service_groups = []
paths = [
".//shared/service-group/entry",
".//devices/entry/vsys/entry/service-group/entry"
]
for path in paths:
for group in self.root.findall(path):
name = group.get('name')
members = []
# Membres
for member in group.findall('members/member'):
members.append(member.text)
obj = ServiceGroup(name=name, members=members)
# Description
desc = group.find('description')
if desc is not None:
obj.description = desc.text
# Misc
misc_elem = group.find('tag')
if misc_elem is not None:
for member in misc_elem.findall('member'):
obj.misc.append(member.text)
service_groups.append(obj)
self.config['service_groups'] = service_groups
print(f"✓ Trouvé {len(service_groups)} groupes de services")
def _parse_interfaces(self):
"""Parse les interfaces réseau"""
interfaces = []
# Interfaces Ethernet
for interface in self.root.findall(".//devices/entry/network/interface/ethernet/entry"):
name = interface.get('name')
obj = Interface(name=name, interface_type='ethernet')
# Adresse IP
layer3 = interface.find('layer3')
if layer3 is not None:
ip_elem = layer3.find('ip/entry')
if ip_elem is not None:
ip_name = ip_elem.get('name')
if '/' in ip_name:
obj.ip, netmask = ip_name.split('/')
obj.netmask = netmask
else:
obj.ip = ip_name
# VLAN misc
misc_elem = interface.find('layer3/tag')
if misc_elem is not None:
obj.misc = int(misc_elem.text)
# Commentaire
comment = interface.find('comment')
if comment is not None:
obj.comment = comment.text
interfaces.append(obj)
# Interfaces Aggregate Ethernet
for interface in self.root.findall(".//devices/entry/network/interface/aggregate-ethernet/entry"):
name = interface.get('name')
obj = Interface(name=name, interface_type='aggregate-ethernet')
# Adresse IP
layer3 = interface.find('layer3')
if layer3 is not None:
ip_elem = layer3.find('ip/entry')
if ip_elem is not None:
ip_name = ip_elem.get('name')
if '/' in ip_name:
obj.ip, netmask = ip_name.split('/')
obj.netmask = netmask
else:
obj.ip = ip_name
# VLAN misc
misc_elem = interface.find('layer3/tag')
if misc_elem is not None:
obj.misc = int(misc_elem.text)
# Commentaire
comment = interface.find('comment')
if comment is not None:
obj.comment = comment.text
interfaces.append(obj)
self.config['interfaces'] = interfaces
print(f"✓ Trouvé {len(interfaces)} interfaces")
def _parse_virtual_routers(self):
"""Parse les virtual-routers et leurs routes statiques"""
virtual_routers = []
for vr_entry in self.root.findall(".//virtual-router/entry"):
vr_name = vr_entry.get("name")
interfaces = [iface.text for iface in vr_entry.findall(".//interface/member")]
static_routes = []
for route_entry in vr_entry.findall(".//routing-table/ip/static-route/entry"):
name = route_entry.get("name")
destination = route_entry.findtext("destination")
metric = int(route_entry.findtext("metric", "0"))
next_vr = route_entry.findtext("nexthop/next-vr")
next_hop_ip = route_entry.findtext("nexthop/ip-address")
interface = route_entry.findtext("interface")
bfd_profile = route_entry.findtext("bfd/profile")
static_route = StaticRoute(
name=name,
destination=destination,
metric=metric,
next_vr=next_vr,
next_hop_ip=next_hop_ip,
interface=interface,
bfd_profile=bfd_profile
)
static_routes.append(static_route)
virtual_routers.append(
VirtualRouter(
name=vr_name,
interfaces=interfaces,
static_routes=static_routes
)
)
self.config['virtual_routers'] = virtual_routers
print(f"✓ Trouvé {len(virtual_routers)} virtual-routers")
def _parse_security_rules(self):
"""Parse les règles de sécurité"""
security_rules = []
rule_types = [
("security", ".//devices/entry/vsys/entry/rulebase/security/rules/entry"),
("nat", ".//devices/entry/vsys/entry/rulebase/nat/rules/entry"),
("default", ".//devices/entry/vsys/entry/rulebase/default-security-rules/rules/entry")
]
for rule_type, xpath in rule_types:
for rule in self.root.findall(xpath):
name = rule.get('name')
# Zones source
from_zones = []
from_elem = rule.find('from')
if from_elem is not None:
for member in from_elem.findall('member'):
from_zones.append(member.text)
# Zones destination
to_zones = []
to_elem = rule.find('to')
if to_elem is not None:
for member in to_elem.findall('member'):
to_zones.append(member.text)
# Adresses source
source_addresses = []
source_elem = rule.find('source')
if source_elem is not None:
for member in source_elem.findall('member'):
source_addresses.append(member.text)
# Adresses destination
destination_addresses = []
destination_elem = rule.find('destination')
if destination_elem is not None:
for member in destination_elem.findall('member'):
destination_addresses.append(member.text)
# Applications
applications = []
app_elem = rule.find('application')
if app_elem is not None:
for member in app_elem.findall('member'):
applications.append(member.text)
# Services
services = []
service_elem = rule.find('service')
if rule_type != "nat":
if service_elem is not None:
for member in service_elem.findall('member'):
services.append(member.text)
else:
services.append(service_elem.text)
# Statut (enabled/disabled)
enabled = True
rule.find('disabled')
if rule.find('disabled') is not None and rule.find('disabled').text == 'yes':
enabled = False
# Misc
miscs = [m.text for m in rule.findall('tag/member')]
# Log setting
log_elem = rule.find('log-setting')
log_setting = log_elem.text if log_elem is not None else "default"
# Action
if rule_type == "nat":
action = 'nat'
else:
action = 'deny'
action_elem = rule.find('action')
if action_elem is not None:
action = action_elem.text
obj = SecurityRule(
name=name,
from_zones=from_zones,
to_zones=to_zones,
source_addresses=source_addresses,
destination_addresses=destination_addresses,
applications=applications,
services=services,
miscs=miscs,
action=action,
log_setting=log_setting,
enabled=enabled
)
# Description
desc = rule.find('description')
if desc is not None:
obj.description = desc.text
# Statut (enabled/disabled)
disabled = rule.find('disabled')
if disabled is not None and disabled.text == 'yes':
obj.enabled = False
if rule_type == "nat":
dt = rule.find('destination-translation')
translated_address = dt.findtext('translated-address', "") if dt is not None else ""
translated_port = dt.findtext('translated-port', "any") if dt is not None else "any"
to_interface = rule.find('to-interface')
else:
translated_address = None
translated_port = None
if rule_type == "nat":
obj.translated_address = translated_address
obj.translated_port = translated_port
obj.to_interface = to_interface.text if to_interface is not None else ""
security_rules.append(obj)
self.config['security_rules'] = security_rules
print(f"✓ Trouvé {len(security_rules)} règles de sécurité")
def parse_all(self):
"""Parse tous les éléments de configuration"""
print("Début du parsing de la configuration Palo Alto...")
self.load_xml()
self._parse_address_objects()
self._parse_address_groups()
self._parse_service_objects()
self._parse_service_groups()
self._parse_interfaces()
self._parse_virtual_routers()
self._parse_security_rules()
print("✓ Parsing terminé avec succès!")
def export_to_json(self, output_file: str):
"""Exporte la configuration au format JSON OpenConfig"""
openconfig_data = self.to_openconfig_yang("palo-alto")
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(openconfig_data, f, indent=2, ensure_ascii=False)
print(f"✓ Configuration exportée vers: {output_file}")
def generate_json_paloalto(input_file: str, output_file: str):
"""Génère le fichier JSON OpenConfig à partir du fichier XML Palo Alto"""
xml_file = Path(input_file)
if not xml_file.exists():
print(f"✗ Erreur: Le fichier '{xml_file}' n'existe pas")
return
try:
parser = PaloAltoParser(str(xml_file))
parser.parse_all()
parser.print_summary()
output_file = output_file
parser.export_to_json(output_file)
print(f"\n✓ Conversion terminée! Vérifiez le fichier: {output_file}")
except Exception as e:
print(f"✗ Erreur: {e}")
return
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print("Usage: python json_PaloAlto.py <fichier_config.xml>")
print("Exemple: python json_PaloAlto.py config_palo_alto.xml")
sys.exit(1)
xml_file = sys.argv[1]
if not Path(xml_file).exists():
print(f"✗ Erreur: Le fichier '{xml_file}' n'existe pas")
sys.exit(1)
try:
parser = PaloAltoParser(xml_file)
parser.parse_all()
parser.print_summary()
input_path = Path(xml_file)
output_file = 'output_PaloAlto.json'
parser.export_to_json(output_file)
print(f"\n✓ Conversion terminée! Vérifiez le fichier: {output_file}")
except Exception as e:
print(f"✗ Erreur: {e}")
sys.exit(1)

View File

@@ -0,0 +1,405 @@
#!/usr/bin/env python3
"""
Parser pour configuration Stormshield vers un format json normalisé OpenConfig YANG
Extrait les groupes d'objets, objets, groupes de services, services, routes, interfaces et règles
"""
from dataclasses import dataclass
import os
import re
import json
from scripts.export_modele import ParserMixin
from scripts.objets.data import AddressObject, AddressGroup, ServiceObject, ServiceGroup, Interface, SecurityRule, StaticRoute, VirtualRouter
from pathlib import Path
class StormshieldParser(ParserMixin):
"""Parser pour dossier Stormshield"""
def __init__(self, base_dir: str):
"""Initialise le parser avec le chemin du dossier Stormshield"""
self.base_dir = base_dir
self.config = {
"address_objects": [],
"address_groups": [],
"service_objects": [],
"service_groups": [],
"interfaces": [],
"virtual_routers": [],
'static_routes': [],
"security_rules": [],
"default_route": None # Ajout Stormshield
}
def _parse_address_objects(self):
"""Parse le fichier object contenant [Host], [Network], [Service], etc."""
current_section = None
path = os.path.join(self.base_dir, "object")
with open(path, "r", encoding="utf-8", errors="ignore") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
if line.startswith("[") and line.endswith("]"):
current_section = line.strip("[]")
continue
if current_section in ("Host", "Network", "Fqdn"):
match = re.match(r"([^=]+)=([^,#]+)", line)
if match:
name = match.group(1).strip()
ip = match.group(2).strip()
self.config["address_objects"].append(
AddressObject(name=name, ip_netmask=ip)
)
elif current_section == "Service":
match = re.match(r"([^=]+)=([\d\-]+)/(\w+)", line)
if match:
name = match.group(1).strip()
port = match.group(2)
proto = match.group(3).lower()
self.config["service_objects"].append(
ServiceObject(name=name, protocol=proto, port=port)
)
def _parse_address_groups(self):
"""Parse le fichier objectgroup pour groupes dadresses"""
current_group = None
members = []
path = os.path.join(self.base_dir, "objectgroup")
with open(path, "r", encoding="utf-8", errors="ignore") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
if line.startswith("[") and "]" in line:
if current_group:
self.config["address_groups"].append(
AddressGroup(name=current_group, members=members)
)
current_group = line.split("]")[0][1:].strip()
members = []
continue
if current_group:
member = line.split("#")[0].strip()
if member:
members.append(member)
if current_group:
self.config["address_groups"].append(
AddressGroup(name=current_group, members=members)
)
def _parse_service_groups(self):
"""Parse le fichier servicegroup pour groupes de services"""
current_group = None
members = []
path = os.path.join(self.base_dir, "servicegroup")
with open(path, "r", encoding="utf-8", errors="ignore") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
if line.startswith("[") and "]" in line:
if current_group:
self.config["service_groups"].append(
ServiceGroup(name=current_group, members=members)
)
current_group = line.split("]")[0][1:].strip()
members = []
continue
if current_group:
member = line.split("#")[0].strip()
if member:
members.append(member)
if current_group:
self.config["service_groups"].append(
ServiceGroup(name=current_group, members=members)
)
def _parse_interfaces(self):
"""Analyse du fichier network et extraction des interfaces"""
current_section = None
current_data = {}
path = os.path.join(self.base_dir, "network")
with open(path, "r", encoding="utf-8", errors="ignore") as f:
for raw_line in f:
line = raw_line.strip()
if not line or line.startswith("#"):
continue
if line.startswith("[") and line.endswith("]"):
if current_section and current_section.lower() != "config":
self._add_interface(current_section, current_data)
current_section = line.strip("[]")
current_data = {}
continue
if "=" in line:
key, value = line.split("=", 1)
key = key.strip()
value = value.split("#")[0].strip()
current_data[key] = value
if current_section and current_section.lower() != "config":
self._add_interface(current_section, current_data)
def _add_interface(self, section_name, data):
"""Crée un objet Interface à partir dune section complète"""
if section_name.lower().startswith("vlan"):
iface_type = "vlan"
elif section_name.lower().startswith("bridge"):
iface_type = "bridge"
elif section_name.lower().startswith("wifi"):
iface_type = "wifi"
elif section_name.lower().startswith("loopback"):
iface_type = "loopback"
elif section_name.lower().startswith("agg"):
iface_type = "aggregate"
else:
iface_type = "ethernet"
enabled = data.get("State", "0") == "1"
name = data.get("Name", section_name)
ip = data.get("Address")
netmask = data.get("Mask")
misc = data.get("Misc")
comment = data.get("Comment", "")
if not name or name.lower() == "dynamic":
return
interface = Interface(
name=name,
ip=ip if ip and ip.upper() != "DHCP" else None,
netmask=netmask,
misc=int(misc) if misc and misc.isdigit() else None,
comment=comment,
interface_type=iface_type,
enabled=enabled,
)
self.config["interfaces"].append(interface)
def _parse_virtual_routers(self):
route_path = os.path.join(self.base_dir, "route")
if not os.path.exists(route_path):
return
section = None
with open(route_path, encoding="utf-8", errors="ignore") as f:
for raw_line in f:
line = raw_line.strip()
if not line or line.startswith("#"):
continue
if line.startswith("[") and line.endswith("]"):
section = line.strip("[]")
continue
if section == "Config" and line.startswith("DefaultRoute="):
self.config["default_route"] = line.split("=", 1)[1].strip()
elif section == "StaticRoutes" and not line.startswith("#"):
parts = line.split(",")
if len(parts) >= 2:
self.config["static_routes"].append({
"destination": parts[0],
"interface": parts[1],
"extra": parts[2:] if len(parts) > 2 else []
})
static_routes = []
if self.config["default_route"]:
static_routes.append(
StaticRoute(
name="default-route",
destination="0.0.0.0/0",
metric=1,
next_hop_ip=self.config["default_route"],
interface=None
)
)
for idx, route in enumerate(self.config["static_routes"]):
static_routes.append(
StaticRoute(
name=f"static-{idx+1}",
destination=route["destination"],
metric=1,
next_hop_ip=None,
interface=route["interface"]
)
)
vr = VirtualRouter(
name="default-vr",
interfaces=[r["interface"] for r in self.config["static_routes"]],
static_routes=static_routes
)
self.config["virtual_routers"] = [vr]
# def _parse_slotinfo_file(self):
# path = os.path.join(self.base_dir, "Filter", "slotinfo")
# if not os.path.exists(path):
# return
# current = None
# with open(path, encoding="utf-8", errors="ignore") as f:
# for raw_line in f:
# line = raw_line.strip()
# if not line or line.startswith("#"):
# continue
# if line.startswith("[") and line.endswith("]"):
# current = line.strip("[]")
# continue
# if current and line.startswith("Name="):
# name = line.split("=", 1)[1].strip('"')
# if name:
# self.filter_slots[current] = name
def _parse_security_rules(self):
filter_dir = os.path.join(self.base_dir, "Filter")
if not os.path.exists(filter_dir):
return
rule_regex = re.compile(
r'^(?P<disabled>off\s+)?'
r'(?P<action>pass|block|nat)\b'
r'(?:\s+noconnlog)?'
r'(?:\s+all)?'
r'(?:\s+inspection)?'
r'(?:\s+firewall)?'
r'(?:\s+route\s+[^\s]+)?'
r'(?:\s+ipproto\s+[^\s]+)?'
r'(?:\s+type\s+\d+)?'
r'(?:\s+code\s+\d+)?'
r'(?:\s+proto\s+[^\s]+)?'
r'\s+from\s+(?P<src>[^\s]+)'
r'(?:\s+on\s+(?P<zone>[^\s]+))?'
r'\s+to\s+(?P<dst>[^\s]+)'
r'(?:\s+port\s+(?P<ports>[^\s]+))?'
r'(?:\s+rulename\s+"(?P<rulename>[^"]+)")?',
re.IGNORECASE
)
slotinfo_path = os.path.join(filter_dir, "slotinfo")
active_slot = "Global"
if os.path.exists(slotinfo_path):
with open(slotinfo_path, encoding="utf-8", errors="ignore") as f:
for raw_line in f:
line = raw_line.strip()
if line.startswith("Active="):
active_slot = line.split("=", 1)[1].strip()
break
for filename in sorted(os.listdir(filter_dir)):
if not re.fullmatch(r"\d{2}", filename):
continue
if filename.lstrip("0") != active_slot:
enabled = False
else:
enabled = True
path = os.path.join(filter_dir, filename)
with open(path, encoding="utf-8", errors="ignore") as f:
for raw_line in f:
line = raw_line.strip()
if not line or line.startswith("separator") or line.startswith("["):
continue
match = rule_regex.match(line)
if not match:
continue
data = match.groupdict()
# ----- Détermination de l'action finale -----
action_raw = data["action"].lower()
if action_raw == "nat":
final_action = "nat"
elif action_raw == "pass":
final_action = "allow"
elif action_raw == "block":
final_action = "block"
else:
final_action = "unknown"
rule = SecurityRule(
name=data.get("rulename")
or f"rule_{filename}_{len(self.config['security_rules'])}",
from_zones=[data.get("zone")] if data.get("zone") else [],
to_zones=[],
source_addresses=[data.get("src") or "any"],
destination_addresses=[data.get("dst") or "any"],
services=data["ports"].split("|") if data.get("ports") else [],
applications=["any"],
action=final_action,
description=self._extract_comment(raw_line),
enabled=enabled
)
self.config["security_rules"].append(rule)
def _extract_comment(self, line: str) -> str:
"""Extrait un commentaire après #"""
if "#" in line:
return line.split("#", 1)[1].strip()
return ""
def parse_all(self):
print("🔍 Parsing de la configuration Stormshield...")
self._parse_virtual_routers()
self._parse_address_objects()
self._parse_address_groups()
self._parse_service_groups()
self._parse_interfaces()
self._parse_security_rules()
print("✓ Parsing terminé avec succès!")
def export_to_json(self, output_file: str):
"""Exporte la configuration au format JSON OpenConfig"""
openconfig_data = self.to_openconfig_yang("stormshield")
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(openconfig_data, f, indent=2, ensure_ascii=False)
print(f"✓ Configuration exportée vers: {output_file}")
def generate_json_stormshield(input_dir: str, output_file: str):
input_dir = input_dir + "/usr/Firewall/ConfigFiles/"
parser = StormshieldParser(input_dir)
parser.parse_all()
parser.print_summary()
output_file = output_file
parser.export_to_json(output_file)
print(f"\n✓ Conversion terminée! Vérifiez le fichier: {output_file}")
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print("Usage: python json_Stormshield.py <dossier>")
sys.exit(1)
input_dir = sys.argv[1]
if not Path(input_dir).exists():
print(f"Erreur : dossier '{input_dir}' inexistant")
sys.exit(1)
output_path = Path("output_Stormshield.json")
generate_json_stormshield(input_dir, str(output_path))

View File

@@ -0,0 +1,95 @@
from dataclasses import dataclass
from typing import List
@dataclass
class AddressObject:
"""Objet adresse"""
name: str
ip_netmask: str = None
description: str = None
misc: List[str] = None
def __post_init__(self):
if self.misc is None:
self.misc = []
@dataclass
class AddressGroup:
"""Groupe d'adresses"""
name: str
members: List[str]
description: str = None
misc: List[str] = None
def __post_init__(self):
if self.misc is None:
self.misc = []
@dataclass
class ServiceObject:
"""Objet service"""
name: str
protocol: str = None
port: str = None
source_port: str = None
description: str = None
misc: List[str] = None
def __post_init__(self):
if self.misc is None:
self.misc = []
@dataclass
class ServiceGroup:
"""Groupe de services"""
name: str
members: List[str]
description: str = None
misc: List[str] = None
def __post_init__(self):
if self.misc is None:
self.misc = []
@dataclass
class Interface:
"""Interface réseau"""
name: str
ip: str = None
netmask: str = None
misc: int = None
comment: str = None
interface_type: str = None
enabled: bool = True
@dataclass
class SecurityRule:
"""Règle de sécurité"""
name: str
from_zones: List[str]
to_zones: List[str]
source_addresses: List[str]
destination_addresses: List[str]
applications: List[str]
services: List[str]
action: str
description: str = None
enabled: bool = True
log_setting: str = "default"
miscs: List[str] = None
@dataclass
class StaticRoute:
name: str
destination: str
metric: int
next_vr: str = None
next_hop_ip: str = None
interface: str = None
bfd_profile: str = None
@dataclass
class VirtualRouter:
name: str
interfaces: List[str]
static_routes: List[StaticRoute]

View File

@@ -0,0 +1,62 @@
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
from openpyxl.utils import get_column_letter
center = Alignment(horizontal="center", vertical="center")
left = Alignment(horizontal="left", vertical="center")
red_fill = PatternFill(start_color="FF9999", fill_type="solid")
orange_fill = PatternFill(start_color="FFCC99", fill_type="solid")
yellow_fill = PatternFill(start_color="FFFF99", fill_type="solid")
thick_border = Border(*(Side(style="thick"),)*4)
thin_border = Border(*(Side(style="thin"),)*4)
def style_address_groups(ws, address_groups):
col_group, col_member, col_ip = 1, 2, 3
start_row = 2
max_width = {1: 0, 2: 0, 3: 0}
for row in range(2, ws.max_row + 1):
g = ws.cell(row=row, column=col_group).value
m = ws.cell(row=row, column=col_member).value
ip = ws.cell(row=row, column=col_ip).value
ws.cell(row=row, column=col_group).fill = red_fill
ws.cell(row=row, column=col_group).font = Font(bold=True)
ws.cell(row=row, column=col_group).border = thin_border
member_fill = orange_fill if m in address_groups else yellow_fill
ws.cell(row=row, column=col_member).fill = member_fill
ws.cell(row=row, column=col_ip).fill = member_fill
ws.cell(row=row, column=col_member).alignment = left
ws.cell(row=row, column=col_ip).alignment = left
ws.cell(row=row, column=col_member).border = thin_border
ws.cell(row=row, column=col_ip).border = thin_border
max_width[1] = max(max_width[1], len(str(g)))
max_width[2] = max(max_width[2], len(str(m)))
max_width[3] = max(max_width[3], len(str(ip)))
next_val = ws.cell(row=row+1, column=col_group).value if row < ws.max_row else None
if g != next_val:
ws.merge_cells(start_row=start_row, start_column=col_group,
end_row=row, end_column=col_group)
for r in range(start_row, row + 1):
ws.cell(r, col_group).border = thick_border
ws.cell(r, col_member).border = thick_border
ws.cell(r, col_ip).border = thick_border
ws.cell(r, col_group).alignment = center
start_row = row + 1
for col in max_width:
ws.column_dimensions[get_column_letter(col)].width = max_width[col] + 2
for row in range(2, ws.max_row + 1):
ws.row_dimensions[row].height = 18

View File

@@ -0,0 +1,65 @@
from openpyxl.styles import Alignment, PatternFill, Font, Border, Side
from openpyxl.utils import get_column_letter
center = Alignment(horizontal="center", vertical="center")
left = Alignment(horizontal="left", vertical="center")
wrap_left = Alignment(horizontal="left", vertical="center", wrap_text=True)
header_fill = PatternFill(start_color="B4C6E7", fill_type="solid")
section_fill = PatternFill(start_color="D9E1F2", fill_type="solid")
thin_border = Border(*(Side(style="thin"),)*4)
def format_cell_multiline(value):
"""Convert comma-separated or list-style text into multiline text"""
if value is None:
return ""
val = str(value).strip()
if val.startswith("[") and val.endswith("]"):
val = val[1:-1]
val = val.replace("'", "").replace('"', "")
return val.replace(", ", "\n").replace(";", "\n").replace(",", "\n").replace(";", "\n")
def style_matrice_flux(ws):
headers = [
("Description",2),("Source",4),("Destination",4),
("Application",1),("Port",1),("Miscellaneous",1),("Action",1),("Tier",1),("Active",1)
]
col = 1
for label, span in headers:
ws.merge_cells(start_row=1, start_column=col, end_row=1, end_column=col + span - 1)
c = ws.cell(row=1, column=col, value=label)
c.alignment = center
c.fill = section_fill
c.font = Font(bold=True)
col += span
wrap_cols = ["Description", "Src Equipement", "Dst Equipement",
"Application", "Port", "Src CIDR", "Dst CIDR", "Src Site", "Dst Site", "Miscellaneous", "Action", "Tier", "Active"]
wrap_indexes = []
for col_idx, cell in enumerate(ws[2], start=1):
if cell.value in wrap_cols:
wrap_indexes.append(col_idx)
for row in ws.iter_rows(min_row=2, max_row=ws.max_row):
for cell in row:
if cell.row > 2:
if cell.col_idx in wrap_indexes:
cell.value = format_cell_multiline(cell.value)
cell.alignment = wrap_left
else:
cell.alignment = left
else:
cell.font = Font(bold=True)
cell.alignment = center
cell.fill = header_fill
cell.border = thin_border
col_widths = {
"A": 50, "B": 35, "C": 35, "D": 18, "E": 15, "F": 15,
"G": 35, "H": 18, "I": 15, "J": 15, "K": 12, "L": 20,
"M": 25, "N": 9, "O": 7, "P": 7
}
for col_letter, width in col_widths.items():
ws.column_dimensions[col_letter].width = width

View File

@@ -0,0 +1,59 @@
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
from openpyxl.utils import get_column_letter
center = Alignment(horizontal="center", vertical="center")
left = Alignment(horizontal="left", vertical="center")
red_fill = PatternFill(start_color="FF9999", fill_type="solid")
orange_fill = PatternFill(start_color="FFCC99", fill_type="solid")
yellow_fill = PatternFill(start_color="FFFF99", fill_type="solid")
thick_border = Border(*(Side(style="thick"),)*4)
thin_border = Border(*(Side(style="thin"),)*4)
def style_service_groups(ws, service_groups):
col_group, col_member, col_proto, col_port = 1, 2, 3, 4
start_row = 2
max_width = {1: 0, 2: 0, 3: 0, 4: 0}
for row in range(2, ws.max_row + 1):
g = ws.cell(row=row, column=col_group).value
m = ws.cell(row=row, column=col_member).value
proto = ws.cell(row=row, column=col_proto).value
port = ws.cell(row=row, column=col_port).value
ws.cell(row=row, column=col_group).fill = red_fill
ws.cell(row=row, column=col_group).font = Font(bold=True)
ws.cell(row=row, column=col_member).fill = (
orange_fill if m in service_groups else yellow_fill
)
ws.cell(row=row, column=col_proto).fill = yellow_fill
ws.cell(row=row, column=col_port).fill = yellow_fill
for col in range(1, 5):
ws.cell(row=row, column=col).border = thin_border
max_width[1] = max(max_width[1], len(str(g or "")))
max_width[2] = max(max_width[2], len(str(m or "")))
max_width[3] = max(max_width[3], len(str(proto or "")))
max_width[4] = max(max_width[4], len(str(port or "")))
next_val = ws.cell(row=row + 1, column=col_group).value if row < ws.max_row else None
if g != next_val:
if row > start_row:
ws.merge_cells(f"A{start_row}:A{row}")
for r in range(start_row, row + 1):
for c in range(1, 5):
ws.cell(r, c).border = thick_border
ws.cell(r, c).alignment = center if c in [1, 3, 4] else left
start_row = row + 1
for col, width in max_width.items():
ws.column_dimensions[get_column_letter(col)].width = width + 4
for row in range(2, ws.max_row + 1):
ws.row_dimensions[row].height = 18

View File

@@ -0,0 +1,21 @@
import sys
import os
from pathlib import Path
sys.path.append(os.path.dirname(__file__))
from scripts.mermaid import NetworkAnalyzer
from scripts.parse_uplinks import UplinkReportGenerator
def main():
"""Fonction principale du programme d'analyse."""
if len(sys.argv) != 2:
print("Usage: python main.py <fichier_log_coeur>")
sys.exit(1)
coeur_log_filename = sys.argv[1]
coeur_log_filename = os.path.basename(coeur_log_filename)
UplinkReportGenerator().generate_report(coeur_log_filename)
NetworkAnalyzer(base_dir=Path(__file__).parent).analyze(coeur_log_filename)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,640 @@
import os
import re
import json
import glob
import sys
from datetime import datetime
class InterfaceParser:
"""
Parses 'display interface' command output to extract interface details.
"""
def parse(self, content: str) -> dict:
interfaces = {}
current_interface = None
lines = content.split('\n')
for line in lines:
line = line.strip()
if re.match(r'^(?!\s)(?:interface\s*)?(?:[A-Za-z-]*Ethernet|Bridge-Aggregation|Vlan-interface)\d+', line):
current_interface = line
interfaces[current_interface] = {
"name": current_interface,
"current_state": None,
"description": None,
"speed_mode": None,
"pvid": None,
"port_channel": None,
"bridge_name": None,
"type": None,
"access_vlan": None,
"trunk_vlans": [],
"ip_address": None,
"shutdown": False,
"config_description": None,
"nb_liens": None,
"mac_destination": None
}
continue
if current_interface and line:
if line.startswith('Current state:'):
interfaces[current_interface]["current_state"] = line.split(':', 1)[1].strip()
elif line.startswith('Description:'):
description = line.split(':', 1)[1].strip()
if description and description != f"{current_interface} Interface":
interfaces[current_interface]["description"] = description
else:
interfaces[current_interface]["description"] = None
elif 'speed mode' in line.lower():
speed_match = re.search(r'(\d+(?:\.\d+)?)\s*(Gbps|Mbps|kbps)[^\w]*speed\s+mode', line, re.I)
if speed_match:
speed_value = speed_match.group(1)
speed_unit = speed_match.group(2)
interfaces[current_interface]["speed_mode"] = f"{speed_value}{speed_unit}"
elif 'pvid' in line.lower():
pvid_match = re.search(r'pvid[:\s]*(\d+)', line, re.I)
if pvid_match:
interfaces[current_interface]["pvid"] = int(pvid_match.group(1))
elif 'port channel' in line.lower() or 'channel group' in line.lower():
pc_match = re.search(r'(?:port channel|channel group)[:\s]*(\d+)', line, re.I)
if pc_match:
interfaces[current_interface]["port_channel"] = int(pc_match.group(1))
elif 'member of bridge-aggregation' in line.lower():
ba_match = re.search(r'member of bridge-aggregation\s*(\d+)', line, re.I)
if ba_match:
interfaces[current_interface]["port_channel"] = int(ba_match.group(1))
return interfaces
class LinkAggregationParser:
"""
Parses 'display link-aggregation verbose' command output.
Extracts link counts, MAC mappings, and bridge mappings.
"""
def _convert_port_name(self, port_name: str) -> str:
"""Converts the port name to a standardized format."""
port_name = re.sub(r'\([A-Z]\)', '', port_name)
patterns = [
(r'^XGE(\d+/\d+/\d+)$', r'Ten-GigabitEthernet\1'),
(r'^GE(\d+/\d+/\d+)$', r'GigabitEthernet\1'),
(r'^FE(\d+/\d+/\d+)$', r'HundredGigE\1'),
(r'^TE(\d+/\d+/\d+)$', r'TenGigabitEthernet\1'),
]
for pattern, replacement in patterns:
if re.match(pattern, port_name):
return re.sub(pattern, replacement, port_name)
return port_name
def parse(self, content: str) -> tuple[dict, dict, dict]:
link_counts = {}
mac_mappings = {}
bridge_mappings = {}
lines = content.split('\n')
current_aggregate = None
current_section = None
local_ports = []
remote_ports = []
for line in lines:
line = line.strip()
if line.startswith('Aggregate Interface:'):
interface_match = re.search(r'Aggregate Interface:\s*(.+)', line)
if interface_match:
current_aggregate = interface_match.group(1).strip()
link_counts[current_aggregate] = 0
local_ports = []
remote_ports = []
continue
if line.startswith('Local:'):
current_section = 'local'
continue
if line.startswith('Remote:'):
current_section = 'remote'
continue
if line.startswith('Aggregate Interface:'):
interface_match = re.search(r'Aggregate Interface:\s*(.+)', line)
if interface_match:
current_aggregate = interface_match.group(1).strip()
if current_aggregate and current_section == 'local' and line:
port_match = re.match(r'^([A-Za-z]+\d+/\d+/\d+(?:\([A-Z]\))?)\s+', line)
if port_match:
if not any(keyword in line for keyword in ['Port', 'Status', 'Priority', 'Index', 'Oper-Key', 'Flag']):
local_port = port_match.group(1)
local_ports.append(local_port)
link_counts[current_aggregate] += 1
if current_aggregate and current_section == 'remote' and line:
remote_match = re.match(r'^([A-Za-z]+\d+/\d+/\d+(?:\([A-Z]\))?)\s+\d+\s+\d+\s+\d+\s+0x[0-9a-fA-F]+,\s*([0-9a-fA-F-]+)', line)
if remote_match:
if not any(keyword in line for keyword in ['Actor', 'Priority', 'Index', 'Oper-Key', 'SystemID', 'Flag']):
remote_port = remote_match.group(1)
system_id = remote_match.group(2)
remote_ports.append((remote_port, system_id))
if current_aggregate and local_ports and remote_ports and \
(line.startswith('Aggregate Interface:') or line == lines[-1].strip()):
min_length = min(len(local_ports), len(remote_ports))
for i in range(min_length):
local_port = local_ports[i]
remote_port, system_id = remote_ports[i]
interface_name = self._convert_port_name(local_port)
mac_mappings[interface_name] = system_id
bridge_mappings[interface_name] = current_aggregate
if line.startswith('Aggregate Interface:'):
current_aggregate = None
local_ports = []
remote_ports = []
current_section = None
if current_aggregate and local_ports and remote_ports:
min_length = min(len(local_ports), len(remote_ports))
for i in range(min_length):
local_port = local_ports[i]
remote_port, system_id = remote_ports[i]
interface_name = self._convert_port_name(local_port)
mac_mappings[interface_name] = system_id
bridge_mappings[interface_name] = current_aggregate
for interface, count in link_counts.items():
if 'Bridge-Aggregation' in interface:
link_counts[interface] = count
return link_counts, mac_mappings, bridge_mappings
class ConfigurationParser:
"""
Parses 'display current-configuration' command output.
Extracts interface configurations and general switch configurations.
"""
def _parse_vlan_ranges(self, vlan_string: str) -> list:
"""Parses a VLAN string and returns a list of unique VLANs."""
vlans = set()
parts = vlan_string.split()
i = 0
while i < len(parts):
if i + 2 < len(parts) and parts[i + 1].lower() == 'to':
try:
start_vlan = int(parts[i])
end_vlan = int(parts[i + 2])
vlans.update(range(start_vlan, end_vlan + 1))
i += 3
except ValueError:
i += 1
else:
try:
vlans.add(int(parts[i]))
except ValueError:
pass
i += 1
return sorted(list(vlans))
def parse(self, content: str) -> tuple[dict, dict]:
interfaces_config = {}
switch_config = {
"version": None,
"lldp": {"enabled": False, "details": {}},
"stp": {"enabled": False, "details": {}},
"ssh": {"enabled": False, "details": {}},
"snmp_contact": None,
"ntp_server": [],
"users": [],
"vlans": []
}
lines = content.split('\n')
current_interface = None
current_section = None
i = 0
while i < len(lines):
line = lines[i]
line_stripped = line.strip()
if line_stripped.startswith('version '):
switch_config["version"] = line_stripped.split('version ', 1)[1].strip()
elif 'lldp enable' in line_stripped.lower():
switch_config["lldp"]["enabled"] = True
elif line_stripped.startswith('lldp '):
switch_config["lldp"]["details"][line_stripped] = True
elif 'stp enable' in line_stripped.lower() or 'spanning-tree' in line_stripped.lower():
switch_config["stp"]["enabled"] = True
switch_config["stp"]["details"][line_stripped] = True
elif 'ssh server enable' in line_stripped.lower() or 'ssh user' in line_stripped.lower():
switch_config["ssh"]["enabled"] = True
switch_config["ssh"]["details"][line_stripped] = True
elif line_stripped.startswith('snmp-agent sys-info contact'):
switch_config["snmp_contact"] = line_stripped.split('contact', 1)[1].strip().strip('"')
elif line_stripped.startswith('ntp-service unicast-server'):
ntp_server = line_stripped.split('unicast-server', 1)[1].strip()
switch_config["ntp_server"].append(ntp_server)
elif line_stripped.startswith('local-user '):
username = line_stripped.split('local-user ', 1)[1].strip()
switch_config["users"].append(username)
elif line_stripped.startswith('vlan '):
vlan_info = line_stripped.split('vlan ', 1)[1].strip()
if "vlans" not in switch_config:
switch_config["vlans"] = []
if 'to' in vlan_info:
parts = vlan_info.split(' to ')
if len(parts) == 2:
start_vlan = int(parts[0])
end_vlan = int(parts[1])
for vlan_id in range(start_vlan, end_vlan + 1):
if vlan_id not in switch_config["vlans"]:
switch_config["vlans"].append(vlan_id)
else:
vlan_id = int(vlan_info)
if vlan_id not in switch_config["vlans"]:
switch_config["vlans"].append(vlan_id)
elif line_stripped.startswith('interface '):
interface_match = re.match(r'^interface\s+(.+)', line_stripped)
if interface_match:
current_interface = interface_match.group(1).strip()
interfaces_config[current_interface] = {
"name": current_interface,
"type": "access",
"access_vlan": None,
"trunk_vlans": [],
"ip_address": None,
"shutdown": False,
"port_channel": None,
"description": None
}
current_section = "interface"
elif current_section == "interface" and current_interface:
if line_stripped != '' and not line.startswith(' ') and not line.startswith('\t'):
if not line_stripped.startswith('interface '):
current_interface = None
current_section = None
continue
else:
interface_match = re.match(r'^interface\s+(.+)', line_stripped)
if interface_match:
current_interface = interface_match.group(1).strip()
interfaces_config[current_interface] = {
"name": current_interface,
"type": "access",
"access_vlan": None,
"trunk_vlans": [],
"ip_address": None,
"shutdown": False,
"port_channel": None,
"description": None
}
elif line.startswith(' ') or line.startswith('\t'):
command = line.strip()
if command.startswith('description '):
interfaces_config[current_interface]["description"] = command.split('description ', 1)[1].strip()
elif command == 'shutdown':
interfaces_config[current_interface]["shutdown"] = True
elif command.startswith('ip address '):
ip_info = command.split('ip address ', 1)[1].strip()
interfaces_config[current_interface]["ip_address"] = ip_info
elif 'link-aggregation' in command.lower() or 'port-group' in command.lower():
pc_match = re.search(r'(\d+)', command)
if pc_match:
interfaces_config[current_interface]["port_channel"] = int(pc_match.group(1))
elif command.startswith('port access vlan '):
vlan_id = int(command.split('port access vlan ', 1)[1].strip())
interfaces_config[current_interface]["type"] = "access"
interfaces_config[current_interface]["access_vlan"] = vlan_id
elif command.startswith('port link-type trunk'):
interfaces_config[current_interface]["type"] = "trunk"
elif command.startswith('port trunk permit vlan '):
interfaces_config[current_interface]["type"] = "trunk"
vlan_info = command.split('port trunk permit vlan ', 1)[1].strip()
if vlan_info == "all":
interfaces_config[current_interface]["trunk_vlans"] = "all"
else:
trunk_vlans = self._parse_vlan_ranges(vlan_info)
interfaces_config[current_interface]["trunk_vlans"].extend(trunk_vlans)
elif command.startswith('undo port trunk permit vlan '):
vlan_info = command.split('undo port trunk permit vlan ', 1)[1].strip()
if vlan_info == "all":
interfaces_config[current_interface]["trunk_vlans"] = []
else:
vlans_to_remove = self._parse_vlan_ranges(vlan_info)
current_trunk = interfaces_config[current_interface]["trunk_vlans"]
if current_trunk != "all":
for vlan in vlans_to_remove:
if vlan in current_trunk:
current_trunk.remove(vlan)
elif command.startswith('port trunk pvid vlan '):
interfaces_config[current_interface]["type"] = "trunk"
pvid = int(command.split('port trunk pvid vlan ', 1)[1].strip())
trunk_vlans = interfaces_config[current_interface]["trunk_vlans"]
if trunk_vlans != "all" and pvid not in trunk_vlans:
trunk_vlans.append(pvid)
i += 1
if isinstance(switch_config["vlans"], list):
switch_config["vlans"] = sorted(list(set(switch_config["vlans"])))
for interface in interfaces_config.values():
if isinstance(interface["trunk_vlans"], list):
interface["trunk_vlans"] = sorted(list(set(interface["trunk_vlans"])))
return interfaces_config, switch_config
class DeviceInfoParser:
"""
Parses 'display device manuinfo' command output to extract MAC addresses.
"""
def parse(self, content: str) -> list[str]:
mac_addresses = []
lines = content.split('\n')
current_slot_cpu = None
for line in lines:
line = line.strip()
if re.match(r'^\s*Slot\s+\d+\s+CPU\s+0\s*:', line, re.I):
current_slot_cpu = line.strip()
continue
if current_slot_cpu and line.startswith('MAC_ADDRESS'):
mac_match = re.search(r'MAC_ADDRESS\s*:\s*([A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4})', line)
if mac_match:
mac_address = mac_match.group(1)
mac_addresses.append(mac_address)
if line.startswith('Slot') and 'CPU' in line and current_slot_cpu:
if line.strip() != current_slot_cpu:
current_slot_cpu = None
return mac_addresses
class LogFileProcessor:
"""
Manages the parsing of a single log file, coordinating different parsers
and merging their results into a unified JSON structure.
"""
def __init__(self):
self.interface_parser = InterfaceParser()
self.link_agg_parser = LinkAggregationParser()
self.config_parser = ConfigurationParser()
self.device_info_parser = DeviceInfoParser()
def _extract_sections(self, file_content: str) -> dict:
"""Extracts different sections from the log file content."""
sections = {}
current_section = None
lines = file_content.splitlines()
section_patterns = {
"display_interface": re.compile(r"^=+\s*display interface\s*=+$", re.I),
"display_link_aggregation_verbose": re.compile(r"^=+\s*display link-aggregation verbose\s*=+$", re.I),
"display_current_configuration": re.compile(r"^=+\s*display current-configuration\s*=+$", re.I),
"display_device_manuinfo": re.compile(r"^=+\s*display device manuinfo\s*=+$", re.I)
}
for line in lines:
line_strip = line.strip()
matched_section = None
for section_name, pattern in section_patterns.items():
if pattern.match(line_strip):
matched_section = section_name
break
if matched_section:
current_section = matched_section
sections[current_section] = []
continue
if re.match(r"^=+$", line_strip):
current_section = None
continue
if current_section:
sections[current_section].append(line)
for key in sections:
sections[key] = "\n".join(sections[key])
return sections
def _extract_switch_name(self, content: str) -> str | None:
"""Extracts the switch name from the log file content."""
sysname_match = re.search(r"(?m)^\s*sysname\s+(.+)$", content)
if sysname_match:
return sysname_match.group(1).strip()
return None
def _merge_configuration_into_interfaces(self, interfaces: dict, interfaces_config: dict):
"""Merges configuration details into the parsed interface data."""
for interface_name, config in interfaces_config.items():
if interface_name in interfaces:
interfaces[interface_name].update({
"type": config["type"],
"access_vlan": config["access_vlan"],
"trunk_vlans": config["trunk_vlans"],
"ip_address": config["ip_address"],
"shutdown": config["shutdown"],
"config_description": config["description"],
})
if config["port_channel"] is not None:
interfaces[interface_name]["port_channel"] = config["port_channel"]
else:
interfaces[interface_name] = {
"name": interface_name,
"current_state": None,
"description": None,
"speed_mode": None,
"pvid": None,
"port_channel": config["port_channel"],
"type": config["type"],
"access_vlan": config["access_vlan"],
"trunk_vlans": config["trunk_vlans"],
"ip_address": config["ip_address"],
"shutdown": config["shutdown"],
"config_description": config["description"],
"nb_liens": None,
"mac_destination": None
}
def _merge_link_aggregation_counts(self, interfaces: dict, link_counts: dict):
"""Merges link aggregation counts into the interface data."""
for interface_name, count in link_counts.items():
if interface_name in interfaces:
interfaces[interface_name]["nb_liens"] = count
def _merge_mac_mappings(self, interfaces: dict, mac_mappings: dict):
"""Merges MAC address mappings into the interface data."""
for interface_name, mac_address in mac_mappings.items():
if interface_name in interfaces:
interfaces[interface_name]["mac_destination"] = mac_address
else:
interfaces[interface_name] = {
"name": interface_name,
"current_state": None,
"description": None,
"speed_mode": None,
"pvid": None,
"port_channel": None,
"type": None,
"access_vlan": None,
"trunk_vlans": [],
"ip_address": None,
"shutdown": False,
"config_description": None,
"nb_liens": None,
"mac_destination": mac_address
}
def _merge_bridge_mappings(self, interfaces: dict, bridge_mappings: dict):
"""Merges bridge aggregation mappings into existing interfaces."""
for interface_name, bridge_name in bridge_mappings.items():
if interface_name in interfaces:
interfaces[interface_name]["bridge_name"] = bridge_name
def process_file(self, filepath: str) -> dict | None:
"""
Processes a single log file to extract and consolidate network device data.
Returns a dictionary containing metadata and parsed data, or None on error.
"""
try:
with open(filepath, 'r', encoding='latin-1', errors='ignore') as f:
content = f.read()
sections = self._extract_sections(content)
if not sections:
return None
mac_addresses = []
if "display_device_manuinfo" in sections:
mac_addresses = self.device_info_parser.parse(sections["display_device_manuinfo"])
result = {
"metadata": {
"filename": os.path.basename(filepath),
"switch_name": self._extract_switch_name(content),
"extraction_date": datetime.now().isoformat(),
"sections_found": list(sections.keys()),
"mac_addresses": mac_addresses
},
"data": {}
}
interfaces = {}
if "display_interface" in sections:
interfaces = self.interface_parser.parse(sections["display_interface"])
if "display_current_configuration" in sections:
try:
interfaces_config, switch_config = self.config_parser.parse(sections["display_current_configuration"])
self._merge_configuration_into_interfaces(interfaces, interfaces_config)
result["data"]["switch_config"] = switch_config
except Exception as e:
print(f" - Error parsing current-configuration for {filepath}: {e}", file=sys.stderr)
result["data"]["switch_config"] = {
"version": None, "lldp": {"enabled": False, "details": {}},
"stp": {"enabled": False, "details": {}}, "ssh": {"enabled": False, "details": {}},
"snmp_contact": None, "ntp_server": [], "users": [], "vlans": []
}
if "display_link_aggregation_verbose" in sections:
try:
link_counts, mac_mappings, bridge_mappings = self.link_agg_parser.parse(sections["display_link_aggregation_verbose"])
self._merge_link_aggregation_counts(interfaces, link_counts)
self._merge_mac_mappings(interfaces, mac_mappings)
self._merge_bridge_mappings(interfaces, bridge_mappings)
except Exception as e:
print(f" - Error parsing link-aggregation verbose for {filepath}: {e}", file=sys.stderr)
result["data"]["interfaces"] = interfaces
return result
except Exception as e:
print(f"Error processing file {filepath}: {e}", file=sys.stderr)
return None
class DataExporter:
"""
Handles the export of processed data to a JSON file.
"""
def export(self, data: dict, output_filepath: str):
try:
output_dir = os.path.dirname(output_filepath)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir)
with open(output_filepath, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"Data saved to: {output_filepath}")
except Exception as e:
print(f"Error saving data to {output_filepath}: {e}", file=sys.stderr)
class MainApplication:
"""
Main application class to orchestrate the log file processing.
"""
def __init__(self):
self.processor = LogFileProcessor()
self.exporter = DataExporter()
def run(self, log_file_pattern: str):
current_dir = os.getcwd()
log_files = glob.glob(os.path.join(current_dir, log_file_pattern))
if not log_files:
print(f"No log files found matching pattern: {log_file_pattern}", file=sys.stderr)
return
results = {}
success_count = 0
for log_file in sorted(log_files):
result = self.processor.process_file(log_file)
if result:
results[os.path.basename(log_file)] = result
success_count += 1
output_file = "./src/data.json"
self.exporter.export(results, output_file)
def process_file_return_json(filepath: str) -> dict | None:
"""
Standalone function to process a single file and return JSON object,
useful for external calls that don't need the full CLI application.
"""
processor = LogFileProcessor()
return processor.process_file(filepath)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python extract_json.py <log_file_pattern>")
else:
app = MainApplication()
app.run(sys.argv[1])

View File

@@ -0,0 +1,254 @@
import sys
import os
from pathlib import Path
from typing import Dict, List, Optional, Any
from dataclasses import dataclass
from contextlib import redirect_stdout
from scripts.extract_json import process_file_return_json
@dataclass
class BridgeInfo:
"""Informations sur un bridge."""
nb_liens: int
speed: str
@classmethod
def from_interface_data(cls, interface_data: Dict[str, Any]) -> 'BridgeInfo':
"""Crée une instance à partir des données d'interface."""
return cls(
nb_liens=interface_data.get("nb_liens", 0),
speed=interface_data.get("speed_mode", "unknown")
)
@dataclass
class InterfaceInfo:
"""Informations sur une interface réseau."""
name: str
mac_destination: Optional[str]
bridge_name: Optional[str]
@classmethod
def from_interface_data(cls, interface_data: Dict[str, Any]) -> 'InterfaceInfo':
"""Crée une instance à partir des données d'interface."""
return cls(
name=interface_data.get("name", ""),
mac_destination=interface_data.get("mac_destination"),
bridge_name=interface_data.get("bridge_name")
)
@dataclass
class DeviceInfo:
"""Informations sur un équipement réseau."""
switch_name: str
mac_addresses: List[str]
interfaces: Dict[str, Any]
@property
def mac_addresses_upper(self) -> List[str]:
"""Retourne les adresses MAC en majuscules."""
return [mac.upper() for mac in self.mac_addresses]
@property
def mac_addresses_str(self) -> str:
"""Retourne les adresses MAC formatées en une chaîne."""
return ','.join(self.mac_addresses_upper)
class LogDataExtractor:
"""Classe pour extraire les données des fichiers de log."""
@staticmethod
def extract_log_data(filename: str) -> Optional[Dict[str, Any]]:
"""Extrait les informations du fichier de log et retourne un dictionnaire."""
try:
data = process_file_return_json(filename)
return data if data else None
except Exception as e:
print(f"Erreur lors du traitement de {filename} : {e}")
sys.exit(1)
@classmethod
def create_device_info(cls, filename: str) -> Optional[DeviceInfo]:
"""Crée un objet DeviceInfo à partir d'un fichier de log."""
data = cls.extract_log_data(filename)
if not data:
return None
metadata = data.get("metadata", {})
return DeviceInfo(
switch_name=metadata.get("switch_name", "unknown"),
mac_addresses=metadata.get("mac_addresses", []),
interfaces=data.get("data", {}).get("interfaces", {})
)
class BridgeAnalyzer:
"""Classe pour analyser les informations de bridge."""
@staticmethod
def extract_bridge_info(interfaces: Dict[str, Any]) -> Dict[str, BridgeInfo]:
"""Extrait les informations de bridge des interfaces."""
bridge_info = {}
for interface_name, interface_data in interfaces.items():
if interface_name.startswith("Bridge-Aggregation"):
bridge_info[interface_name] = BridgeInfo.from_interface_data(interface_data)
return bridge_info
@staticmethod
def get_bridge_details(bridge_info: Dict[str, BridgeInfo], bridge_name: str) -> tuple[str, int]:
"""Récupère les détails d'un bridge spécifique."""
bridge = bridge_info.get(bridge_name, BridgeInfo(0, "unknown"))
return bridge.speed, bridge.nb_liens
class NetworkFormatter:
"""Classe pour formater les sorties réseau."""
@staticmethod
def format_device_output(device_info: DeviceInfo, interface_info: InterfaceInfo,
speed: str, nb_liens: int) -> str:
"""Formate la sortie pour un équipement."""
mac_dest = interface_info.mac_destination.upper() if interface_info.mac_destination else ""
return (f"{device_info.switch_name} [{device_info.mac_addresses_str}] "
f"{interface_info.name} -> {mac_dest} "
f"[{interface_info.bridge_name},{speed},{nb_liens}]")
class CoeurAnalyzer:
"""Classe pour analyser les équipements coeur."""
def __init__(self):
self.mac_coeur = ""
def set_mac_coeur(self, mac_addresses: List[str]) -> None:
"""Met les MAC du coeur dans une variable d'instance."""
self.mac_coeur = ', '.join(mac_addresses)
def analyze(self, filename: str) -> None:
"""Analyse l'extraction json du fichier log du coeur."""
device_info = LogDataExtractor.create_device_info(filename)
if not device_info:
return
# Stocker les MAC du coeur pour les switches
self.set_mac_coeur(device_info.mac_addresses_upper)
bridge_info = BridgeAnalyzer.extract_bridge_info(device_info.interfaces)
for interface_data in device_info.interfaces.values():
interface_info = InterfaceInfo.from_interface_data(interface_data)
if interface_info.mac_destination:
speed, nb_liens = BridgeAnalyzer.get_bridge_details(
bridge_info, interface_info.bridge_name
)
output = NetworkFormatter.format_device_output(
device_info, interface_info, speed, nb_liens
)
print(output)
class SwitchAnalyzer:
"""Classe pour analyser les switches."""
def __init__(self, coeur_analyzer: CoeurAnalyzer):
self.coeur_analyzer = coeur_analyzer
def analyze(self, filename: str) -> None:
"""Analyse l'extraction json du fichier log d'un switch."""
device_info = LogDataExtractor.create_device_info(filename)
if not device_info:
return
bridge_info = BridgeAnalyzer.extract_bridge_info(device_info.interfaces)
for interface_data in device_info.interfaces.values():
interface_info = InterfaceInfo.from_interface_data(interface_data)
if (interface_info.mac_destination and
interface_info.mac_destination.upper() in self.coeur_analyzer.mac_coeur):
speed, nb_liens = BridgeAnalyzer.get_bridge_details(
bridge_info, interface_info.bridge_name
)
output = NetworkFormatter.format_device_output(
device_info, interface_info, speed, nb_liens
)
print(output)
class NetworkAnalysisOrchestrator:
"""Classe principale pour orchestrer l'analyse réseau."""
def __init__(self, base_dir: Path = None):
if base_dir is None:
base_dir = Path(__file__).parent.parent
self.base_dir = Path(base_dir)
self.log_dir = self.base_dir / 'logs'
self.output_file = self.base_dir / 'data.txt'
self.coeur_analyzer = CoeurAnalyzer()
self.switch_analyzer = SwitchAnalyzer(self.coeur_analyzer)
def _get_log_files(self, exclude_filename: str) -> List[Path]:
"""Récupère tous les fichiers de log sauf celui exclu."""
if not self.log_dir.exists():
return []
return [
log_file for log_file in self.log_dir.glob('*.log')
if log_file.name != exclude_filename
]
def run_analysis(self, filename: str) -> None:
"""Lance l'analyse du coeur et des switches à partir d'un fichier log coeur donné."""
coeur_log_path = self.log_dir / filename
if not coeur_log_path.exists():
print(f"Erreur: Le fichier {coeur_log_path} n'existe pas")
return
# Rediriger la sortie vers le fichier
with open(self.output_file, 'w', encoding='utf-8') as f:
with redirect_stdout(f):
print("Coeur:")
self.coeur_analyzer.analyze(str(coeur_log_path))
print("Switches:")
switch_files = self._get_log_files(filename)
for switch_file in switch_files:
self.switch_analyzer.analyze(str(switch_file))
class FormatMain:
"""Classe principale pour le module format."""
def __init__(self, base_dir: Path = None):
self.orchestrator = NetworkAnalysisOrchestrator(base_dir)
def run_analysis(self, filename: str) -> None:
"""Point d'entrée public pour l'analyse."""
self.orchestrator.run_analysis(filename)
def main(filename: str = None) -> None:
"""Fonction principale."""
if filename is None:
if len(sys.argv) != 2:
print("Usage: python format.py <filename>")
sys.exit(1)
filename = sys.argv[1]
format_main = FormatMain()
format_main.run_analysis(filename)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,358 @@
import re
import sys
from collections import defaultdict
from pathlib import Path
from typing import List, Optional, Tuple
from dataclasses import dataclass
from scripts.format import FormatMain
@dataclass
class NetworkDevice:
"""Classe de base pour représenter un équipement réseau."""
name: str
macs: List[str]
interface: str
dest_mac: str
bridge: str
vitesse: str
nb_liens: str
def __post_init__(self):
"""Validation et nettoyage des données après initialisation."""
if isinstance(self.macs, str):
self.macs = [mac.strip() for mac in self.macs.split(',')]
self.bridge = self.bridge.strip()
self.vitesse = self.vitesse.strip()
self.nb_liens = self.nb_liens.strip()
@property
def macs_str(self) -> str:
"""Retourne les MACs sous forme de chaîne formatée."""
return ','.join(self.macs)
def to_formatted_string(self) -> str:
"""Retourne une représentation formatée de l'équipement."""
return f"{self.name} [{self.macs_str}] {self.interface} -> {self.dest_mac} [{self.bridge},{self.vitesse},{self.nb_liens}]"
@dataclass
class Coeur(NetworkDevice):
"""Classe représentant un équipement coeur."""
pass
@dataclass
class Switch(NetworkDevice):
"""Classe représentant un switch."""
pass
class NetworkFileParser:
"""Classe pour parser les fichiers de configuration réseau."""
ENCODINGS = ['utf-8', 'utf-16', 'utf-16-le', 'utf-16-be', 'latin-1', 'cp1252', 'iso-8859-1']
PATTERNS = [
r'(\S+)\s+\[([^\]]+)\]\s+(\S+)\s+->\s+([A-Fa-f0-9:-]+)\s*\[([^,]+),([^,]+),([^\]]+)\]',
r'(\S+)\s+\[([^\]]+)\]\s+(\S+)\s*->\s*([A-Fa-f0-9:-]+)\s*\[([^,]+),([^,]+),([^\]]+)\]',
r'(\w+)\s*\[([^\]]+)\]\s*(\w+)\s*->\s*([A-Fa-f0-9:-]+)\s*\[([^,]+),([^,]+),([^\]]+)\]'
]
def __init__(self, file_path: str):
self.file_path = Path(file_path)
def _read_file_with_encoding(self) -> Optional[str]:
"""Lit le fichier en essayant différents encodages."""
for encoding in self.ENCODINGS:
try:
return self.file_path.read_text(encoding=encoding)
except (UnicodeDecodeError, UnicodeError):
continue
except FileNotFoundError:
return None
return None
def _parse_line(self, line: str, device_class) -> Optional[NetworkDevice]:
"""Parse une ligne et retourne un objet NetworkDevice."""
line = line.strip()
if not line:
return None
for pattern in self.PATTERNS:
match = re.match(pattern, line)
if match:
return device_class(
name=match.group(1),
macs=match.group(2),
interface=match.group(3),
dest_mac=match.group(4),
bridge=match.group(5),
vitesse=match.group(6),
nb_liens=match.group(7)
)
print(f" -> Aucun pattern ne correspond à cette ligne: {line}")
return None
def parse(self) -> Tuple[List[Coeur], List[Switch]]:
"""Parse le fichier et retourne les coeurs et switches."""
content = self._read_file_with_encoding()
if content is None:
return [], []
sections = content.split('Switches:')
if len(sections) < 2:
return [], []
coeur_section = sections[0].replace('Coeur:', '').strip()
switches_section = sections[1].strip()
coeurs = []
for line in coeur_section.split('\n'):
coeur = self._parse_line(line, Coeur)
if coeur:
coeurs.append(coeur)
switches = []
for line in switches_section.split('\n'):
switch = self._parse_line(line, Switch)
if switch:
switches.append(switch)
return coeurs, switches
class NetworkDeviceGrouper:
"""Classe pour grouper les équipements réseau."""
@staticmethod
def group_coeurs_by_dest_mac(coeurs: List[Coeur]) -> List[Coeur]:
"""Groupe les coeurs par adresse MAC de destination."""
grouped = defaultdict(list)
for coeur in coeurs:
key = (coeur.dest_mac, coeur.name, coeur.macs_str,
coeur.bridge, coeur.vitesse, coeur.nb_liens)
grouped[key].append(coeur)
result = []
for key, group in grouped.items():
dest_mac, name, macs_str, bridge, vitesse, nb_liens = key
interfaces = [item.interface for item in group]
result.append(Coeur(
name=name,
macs=macs_str.split(','),
interface='-'.join(interfaces),
dest_mac=dest_mac,
bridge=bridge,
vitesse=vitesse,
nb_liens=nb_liens
))
return result
@staticmethod
def group_switches_by_local_mac(switches: List[Switch]) -> List[Switch]:
"""Groupe les switches par adresse MAC locale."""
grouped = defaultdict(list)
for switch in switches:
key = (switch.name, switch.macs_str, switch.dest_mac,
switch.bridge, switch.vitesse, switch.nb_liens)
grouped[key].append(switch)
result = []
for key, group in grouped.items():
name, macs_str, dest_mac, bridge, vitesse, nb_liens = key
interfaces = [item.interface for item in group]
result.append(Switch(
name=name,
macs=macs_str.split(','),
interface='-'.join(interfaces),
dest_mac=dest_mac,
bridge=bridge,
vitesse=vitesse,
nb_liens=nb_liens
))
return result
class MermaidDiagramGenerator:
"""Classe pour générer les diagrammes Mermaid."""
def __init__(self, coeurs: List[Coeur], switches: List[Switch]):
self.coeurs = coeurs
self.switches = switches
def _find_matching_switch(self, coeur: Coeur) -> Optional[Switch]:
"""Trouve le switch correspondant à un coeur."""
for switch in self.switches:
if coeur.dest_mac in switch.macs:
return switch
return None
def _format_bridge_label(self, bridge: str, vitesse: str) -> str:
"""Formate le label du bridge."""
bridge_formatted = bridge.replace('Bridge-Aggregation', 'BAGG')
return f"{bridge_formatted}<br/>{vitesse}"
def generate_links_diagram(self) -> str:
"""Génère un diagramme Mermaid des liaisons."""
if not self.coeurs or not self.switches:
return "Aucune donnée à afficher"
mermaid_lines = ["graph LR"]
total_devices = min(len(self.coeurs), len(self.switches))
for i, coeur in enumerate(self.coeurs):
target_switch = self._find_matching_switch(coeur)
label = self._format_bridge_label(coeur.bridge, coeur.vitesse)
if target_switch:
if i < total_devices // 2:
line = f' Coeur(("{coeur.name}")) <-->|{label}| {target_switch.name}'
else:
line = f' {target_switch.name} <-->|{label}| Coeur(("{coeur.name}"))'
mermaid_lines.append(line)
else:
line = f' Coeur(("{coeur.name}")) <-->|{label}| {coeur.dest_mac}["📄manquant {coeur.dest_mac}"]'
mermaid_lines.append(line)
mermaid_lines.append(f' class {coeur.dest_mac} error;')
return '\n'.join(mermaid_lines)
class FileWriter:
"""Classe pour l'écriture de fichiers."""
@staticmethod
def write_mermaid_diagram(mermaid_code: str, output_path: Path) -> None:
"""Sauvegarde le diagramme Mermaid."""
try:
output_path.parent.mkdir(parents=True, exist_ok=True)
content = [
"# Diagramme des liaisons Coeur-Switch\n",
"```mermaid\n",
"---\n",
"config:\n",
" theme: 'base'\n",
" themeVariables:\n",
" primaryColor: '#25bb75ff'\n",
" primaryTextColor: '#ffffff'\n",
" primaryBorderColor: '#000000ff'\n",
" lineColor: '#f82929ff'\n",
" secondaryColor: '#5e0c1aff'\n",
" tertiaryColor: '#ffffff'\n",
"---\n",
mermaid_code,
"\nclass Coeur coeur;\n",
"classDef coeur fill:#0590e6;\n",
"classDef error fill:#e64c05;\n",
"\n```\n"
]
output_path.write_text(''.join(content), encoding='utf-8')
print(f"✅ Diagramme Mermaid généré : {output_path}")
except Exception as e:
print(f"Erreur lors de la sauvegarde: {e}")
@staticmethod
def write_grouped_file(coeurs: List[Coeur], switches: List[Switch], output_path: Path) -> None:
"""Écrit les équipements groupés dans un fichier."""
try:
lines = ["Coeur:\n"]
lines.extend(f"{coeur.to_formatted_string()}\n" for coeur in coeurs)
lines.append("Switches:\n")
lines.extend(f"{switch.to_formatted_string()}\n" for switch in switches)
output_path.write_text(''.join(lines), encoding='utf-8')
except Exception as e:
print(f"Erreur lors de la sauvegarde: {e}")
@staticmethod
def write_links_file(coeurs: List[Coeur], switches: List[Switch], output_path: Path) -> None:
"""Écrit les liens entre coeurs et switches."""
try:
lines = []
for coeur in coeurs:
matching_switch = None
for switch in switches:
if coeur.dest_mac in switch.macs:
matching_switch = switch
break
if matching_switch:
coeur_info = f"{coeur.name} [{coeur.macs_str}] {coeur.interface} [{coeur.bridge},{coeur.vitesse},{coeur.nb_liens}]"
switch_info = f"{matching_switch.name} [{matching_switch.macs_str}] {matching_switch.interface} [{matching_switch.bridge},{matching_switch.vitesse},{matching_switch.nb_liens}]"
lines.append(f"{coeur_info} -> {switch_info}\n")
else:
lines.append(f"{coeur.name} [{coeur.macs_str}] {coeur.interface} -> Aucune correspondance de switch pour MAC {coeur.dest_mac}\n")
output_path.write_text(''.join(lines), encoding='utf-8')
except Exception as e:
print(f"Erreur lors de l'écriture des liens: {e}")
class NetworkAnalyzer:
"""Classe principale pour l'analyse réseau."""
def __init__(self, base_dir: Path = None):
if base_dir is None:
base_dir = Path(__file__).parent.parent
self.base_dir = Path(base_dir)
self.data_file = self.base_dir / 'data.txt'
self.output_dir = self.base_dir / 'output'
self.mermaid_file = self.output_dir / 'mermaid.md'
def analyze(self, filename: str) -> None:
"""Analyse complète du réseau."""
# Exécute l'analyse initiale
FormatMain().run_analysis(filename)
# Parse le fichier
parser = NetworkFileParser(self.data_file)
coeurs, switches = parser.parse()
if not coeurs and not switches:
print("Impossible de lire le fichier ou format incorrect")
return
# Groupe les équipements
grouper = NetworkDeviceGrouper()
grouped_coeurs = grouper.group_coeurs_by_dest_mac(coeurs)
grouped_switches = grouper.group_switches_by_local_mac(switches)
# Écrit les fichiers de sortie
writer = FileWriter()
writer.write_grouped_file(grouped_coeurs, grouped_switches, self.data_file)
writer.write_links_file(grouped_coeurs, grouped_switches, self.data_file)
# Génère le diagramme Mermaid
diagram_generator = MermaidDiagramGenerator(grouped_coeurs, grouped_switches)
mermaid_code = diagram_generator.generate_links_diagram()
writer.write_mermaid_diagram(mermaid_code, self.mermaid_file)
def main():
"""Fonction principale."""
if len(sys.argv) != 2:
print("Usage: python mermaid.py <filename>")
sys.exit(1)
analyzer = NetworkAnalyzer()
analyzer.analyze(filename=sys.argv[1])
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,448 @@
import os
import re
import sys
import json
import logging
from typing import Dict, List, Optional, Union, Any
from dataclasses import dataclass
from pathlib import Path
import pandas as pd
from openpyxl import load_workbook
from scripts.extract_json import process_file_return_json
mac_coeur=[]
@dataclass
class Config:
"""Configuration centralisée pour l'application."""
LOGS_DIR: str = './src/logs'
OUTPUT_DIR: str = './src/output'
DATA_JSON_PATH: str = './src/data.json'
OUTPUT_FILE_NAME: str = 'uplink_report.xlsx'
@property
def output_file_path(self) -> str:
return os.path.join(self.OUTPUT_DIR, self.OUTPUT_FILE_NAME)
@dataclass
class InterfaceResult:
"""Résultat d'analyse d'une interface."""
switch: str
logfile: str
interface: str
status: str
speed_gbps: Optional[Union[int, float, str]]
port_channel: Optional[str]
description: str
issues: str
mac_local: Optional[List[str]]
mac_destination: Optional[str]
bridge_name: Optional[str]
bridge_speed: Optional[Union[int, float, str]]
nb_liens: Optional[int]
@dataclass
class LCInterfaceResult:
"""Résultat d'analyse d'une interface LC."""
switch: str
interface: str
status: str
speed_gbps: Optional[Union[int, float, str]]
port_channel: Optional[str]
description: str
type_lien: str
nb_liens: Optional[int]
bridge_utilise: Optional[str]
mac_destination: Optional[str]
switch_destination: str
class InterfaceAnalyzer:
"""Analyseur d'interfaces réseau."""
CORE_INTERLINK_PATTERN = re.compile(r'/0/(49|50)$')
SPEED_PATTERN = re.compile(r"(\d+(?:\.\d+)?)\s*Gbps", re.I)
SHORT_NAME_PATTERN = re.compile(r'(\d+/\d+/\d+)$')
INTERCORE_PATTERN = re.compile(r'[1-4]/0/4[3-8]$')
CORE_INTERFACE_PATTERN = re.compile(r'/0/(4[89]|50)$')
@classmethod
def is_core_interlink(cls, interface_name: str) -> bool:
"""Détermine si l'interface est un lien inter-cœur."""
return cls.CORE_INTERLINK_PATTERN.search(interface_name) is not None
@classmethod
def is_intercore_link(cls, interface_name: str) -> bool:
"""Détermine si l'interface est un lien inter-cœur (LC)."""
return cls.INTERCORE_PATTERN.search(interface_name) is not None
@classmethod
def guess_speed(cls, speed_mode: Optional[str], interface_name: Optional[str] = None) -> Optional[Union[int, float, str]]:
"""Devine la vitesse d'une interface."""
if speed_mode:
match = cls.SPEED_PATTERN.match(speed_mode)
if match:
return float(match.group(1))
if interface_name and cls.CORE_INTERFACE_PATTERN.search(interface_name):
if "Ten-GigabitEthernet" in interface_name:
return 10
elif "GigabitEthernet" in interface_name:
return 1
elif "HundredGigE" in interface_name:
return 100
elif "M-GigabitEthernet" in interface_name:
return "?"
return None
@classmethod
def extract_short_name(cls, interface_name: str) -> str:
"""Extrait le nom court d'une interface."""
match = cls.SHORT_NAME_PATTERN.search(interface_name)
return match.group(1) if match else interface_name
@classmethod
def identify_issues(cls, info: Dict[str, Any], speed: Optional[Union[int, float, str]]) -> List[str]:
"""Identifie les problèmes potentiels d'une interface."""
issues = []
if info.get("current_state") is not None:
if info.get("current_state", "").upper() != "UP":
issues.append("DOWN")
if isinstance(speed, (int, float)) and speed < 10:
issues.append(f"Poss. goulot ({speed} Gbps)")
if info.get("port_channel"):
issues.append(f"Membre Port-Channel {info['port_channel']}")
return issues
class SwitchLogAnalyzer:
"""Analyseur de logs de switchs."""
def __init__(self, config: Config):
self.config = config
self.analyzer = InterfaceAnalyzer()
self.logger = self._setup_logger()
def _setup_logger(self) -> logging.Logger:
"""Configure le logger."""
logger = logging.getLogger(__name__)
if not logger.handlers:
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
return logger
def analyze_switch_log(
self,
filename: str,
switch_name: str,
interfaces: Dict[str, Any],
mac_addresses: Optional[List[str]] = None,
is_core: bool = False,
filter_mac_destination: bool = True
) -> List[InterfaceResult]:
"""Analyse les interfaces d'un switch."""
results = []
for iface_name, info in interfaces.items():
if not self._should_process_interface(info, filter_mac_destination, is_core, iface_name):
continue
result = self._create_interface_result(
filename, switch_name, iface_name, info, interfaces, mac_addresses
)
results.append(result)
return results
def _should_process_interface(
self,
info: Dict[str, Any],
filter_mac_destination: bool,
is_core: bool,
iface_name: str
) -> bool:
"""Détermine si une interface doit être traitée."""
global mac_coeur
if filter_mac_destination and info.get("mac_destination") not in mac_coeur:
return False
if is_core and not self.analyzer.is_core_interlink(iface_name):
return False
return True
def _create_interface_result(
self,
filename: str,
switch_name: str,
iface_name: str,
info: Dict[str, Any],
interfaces: Dict[str, Any],
mac_addresses: Optional[List[str]]
) -> InterfaceResult:
"""Crée un résultat d'interface."""
mac_destination = info.get("mac_destination")
bridge_name = info.get("bridge_name")
bridge_info = interfaces.get(bridge_name, {}) if bridge_name else {}
speed = self.analyzer.guess_speed(info.get("speed_mode"), iface_name)
bridge_speed = self.analyzer.guess_speed(bridge_info.get("speed_mode"), bridge_name)
issues = self.analyzer.identify_issues(info, speed)
description = info.get("description") or info.get("config_description") or ""
return InterfaceResult(
switch=switch_name,
logfile=filename,
interface=iface_name,
status=info.get("current_state", "unknown"),
speed_gbps=speed,
port_channel=info.get("port_channel"),
description=description,
issues=", ".join(issues) if issues else "RAS",
mac_local=mac_addresses,
mac_destination=mac_destination,
bridge_name=bridge_name,
bridge_speed=bridge_speed,
nb_liens=bridge_info.get("nb_liens")
)
def analyze_lc_log(self, filename: str, switch_name: str, interfaces: Dict[str, Any]) -> List[LCInterfaceResult]:
"""Analyse les interfaces LC."""
results = []
for iface_name, info in interfaces.items():
if not info or not isinstance(info, dict):
continue
result = self._create_lc_interface_result(filename, switch_name, iface_name, info)
results.append(result)
return results
def _create_lc_interface_result(
self,
filename: str,
switch_name: str,
iface_name: str,
info: Dict[str, Any]
) -> LCInterfaceResult:
"""Crée un résultat d'interface LC."""
speed = self.analyzer.guess_speed(info.get("speed_mode"), iface_name)
type_lien = "Lien inter-coeur" if self.analyzer.is_intercore_link(iface_name) else "Vers Accès"
description = info.get("description") or info.get("config_description") or ""
nb_liens = info.get("nb_liens") if iface_name.startswith("Bridge-Aggregation") else None
bridge_utilise = None if iface_name.startswith("Bridge-Aggregation") else info.get("bridge_name")
mac_destination = None if iface_name.startswith("Bridge-Aggregation") else info.get("mac_destination")
return LCInterfaceResult(
switch=switch_name,
interface=iface_name,
status=info.get("current_state", "unknown"),
speed_gbps=speed,
port_channel=info.get("port_channel"),
description=description,
type_lien=type_lien,
nb_liens=nb_liens,
bridge_utilise=bridge_utilise,
mac_destination=mac_destination,
switch_destination=""
)
class ExcelReportGenerator:
"""Générateur de rapports Excel."""
def __init__(self, config: Config):
self.config = config
self.logger = logging.getLogger(__name__)
def generate_report(self, uplink_results: List[InterfaceResult], lc_results: List[LCInterfaceResult]) -> None:
"""Génère le rapport Excel."""
df_uplink = self._create_uplink_dataframe(uplink_results)
df_lc = self._create_lc_dataframe(lc_results)
os.makedirs(self.config.OUTPUT_DIR, exist_ok=True)
self._write_excel_file(df_uplink, df_lc)
self._format_excel_file()
print(f"✅ Rapport Excel généré : {self.config.output_file_path}")
def _create_uplink_dataframe(self, results: List[InterfaceResult]) -> pd.DataFrame:
"""Crée le DataFrame pour les uplinks."""
data = []
for result in results:
data.append({
"switch": result.switch,
"logfile": result.logfile,
"interface": result.interface,
"status": result.status,
"speed_gbps": result.speed_gbps,
"port_channel": result.port_channel,
"description": result.description,
"issues": result.issues,
"mac_local": result.mac_local,
"mac_destination": result.mac_destination,
"bridge_name": result.bridge_name,
"bridge_speed": result.bridge_speed,
"nb_liens": result.nb_liens
})
return pd.DataFrame(data)
def _create_lc_dataframe(self, results: List[LCInterfaceResult]) -> pd.DataFrame:
"""Crée le DataFrame pour les interfaces LC."""
data = []
for result in results:
data.append({
"Switch": result.switch,
"Interface": result.interface,
"Status": result.status,
"Vitesse (Gbps)": result.speed_gbps,
"Port-Channel": result.port_channel,
"Description": result.description,
"Type de lien": result.type_lien,
"Nb liens": result.nb_liens,
"Bridge utilisé": result.bridge_utilise,
"MAC destination": result.mac_destination,
"Switch destination": result.switch_destination
})
return pd.DataFrame(data)
def _write_excel_file(self, df_uplink: pd.DataFrame, df_lc: pd.DataFrame) -> None:
"""Écrit le fichier Excel."""
with pd.ExcelWriter(self.config.output_file_path, engine='openpyxl') as writer:
df_uplink.to_excel(writer, index=False, sheet_name="Uplinks")
df_lc.to_excel(writer, index=False, sheet_name="LC_Interfaces")
def _format_excel_file(self) -> None:
"""Met en forme le fichier Excel."""
wb = load_workbook(self.config.output_file_path)
self._add_formulas(wb)
self._format_columns(wb)
wb.save(self.config.output_file_path)
def _add_formulas(self, workbook) -> None:
"""Ajoute les formules Excel."""
ws = workbook["LC_Interfaces"]
for row in range(2, 400):
formula = (
f'=IF(J{row}="","",IFERROR(INDEX(Uplinks!A$2:A$400,'
f'MATCH(TRUE,ISNUMBER(SEARCH(J{row},Uplinks!I$2:I$400)),0)),""))'
)
ws[f'K{row}'] = formula
def _format_columns(self, workbook) -> None:
"""Met en forme les colonnes."""
column_widths = {
"LC_Interfaces": [15, 25, 25, 15, 12, 45, 15, 10, 22, 20, 20],
"Uplinks": [15, 30, 25, 7, 12, 12, 30, 22, 47, 15, 20, 13, 10]
}
for sheet_name, widths in column_widths.items():
ws = workbook[sheet_name]
for col_idx, width in enumerate(widths, start=1):
ws.column_dimensions[chr(64 + col_idx)].width = width
class UplinkReportGenerator:
"""Générateur principal de rapports d'uplink."""
def __init__(self, config: Optional[Config] = None):
self.config = config or Config()
self.analyzer = SwitchLogAnalyzer(self.config)
self.report_generator = ExcelReportGenerator(self.config)
self.logger = logging.getLogger(__name__)
def generate_report(self, lc_filename_prefix: str) -> None:
"""Génère le rapport complet."""
try:
uplink_results, lc_results = self._process_log_files(lc_filename_prefix)
self.report_generator.generate_report(uplink_results, lc_results)
except Exception as e:
self.logger.error(f"Erreur lors de la génération du rapport : {e}")
raise
def _process_log_files(self, lc_filename_prefix: str) -> tuple[List[InterfaceResult], List[LCInterfaceResult]]:
"""Traite tous les fichiers de logs."""
global mac_coeur
uplink_results = []
lc_results = []
log_files = self._get_log_files()
for filename in log_files:
try:
data = self._process_single_log_file(filename)
if not data:
continue
interfaces = data.get("data", {}).get("interfaces", {})
switch_name = data.get("metadata", {}).get("switch_name", "unknown")
if filename.startswith(lc_filename_prefix):
mac_coeur = data.get("metadata", {}).get("mac_addresses", [])
mac_coeur = [mac.lower() for mac in mac_coeur]
lc_results.extend(self.analyzer.analyze_lc_log(filename, switch_name, interfaces))
else:
mac_addresses = data.get("metadata", {}).get("mac_addresses", [])
uplink_results.extend(
self.analyzer.analyze_switch_log(
filename, switch_name, interfaces,
mac_addresses=mac_addresses,
filter_mac_destination=True
)
)
except Exception as e:
self.logger.error(f"Erreur lors du traitement de {filename}: {e}")
continue
return uplink_results, lc_results
def _get_log_files(self) -> List[str]:
"""Récupère la liste des fichiers de logs."""
if not os.path.exists(self.config.LOGS_DIR):
raise FileNotFoundError(f"Le répertoire {self.config.LOGS_DIR} n'existe pas")
return [f for f in os.listdir(self.config.LOGS_DIR) if f.endswith('.log')]
def _process_single_log_file(self, filename: str) -> Optional[Dict[str, Any]]:
"""Traite un fichier de log individuel."""
filepath = os.path.join(self.config.LOGS_DIR, filename)
return process_file_return_json(filepath)
def main():
"""Fonction principale."""
if len(sys.argv) < 2:
print("Usage: python parse_uplinks.py <fichier_log_coeur> (sans chemin)")
sys.exit(1)
lc_filename_prefix = sys.argv[1]
try:
generator = UplinkReportGenerator()
generator.generate_report(lc_filename_prefix)
except Exception as e:
print(f"❌ Erreur : {e}")
sys.exit(1)
if __name__ == "__main__":
main()

349
gui.py Normal file
View File

@@ -0,0 +1,349 @@
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from datetime import datetime
from threading import Thread
import subprocess
import os
import sys
# Chemin
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
FIREWALL_DIR = os.path.join(
BASE_DIR,
"Parseurs_config_Firewall"
)
FIREWALL_MAIN = os.path.join(
FIREWALL_DIR,
"src",
"main.py"
)
HELP_FILE_FW = os.path.join(BASE_DIR, "help_Firewall.md")
OUTPUT_DIR = os.path.join(FIREWALL_DIR, "src", "output")
os.makedirs(OUTPUT_DIR, exist_ok=True)
PYTHON_EXEC = sys.executable
class ToolTip:
def __init__(self, widget, text):
self.widget = widget
self.text = text
self.tipwindow = None
widget.bind("<Enter>", self.show)
widget.bind("<Leave>", self.hide)
def show(self, event=None):
if self.tipwindow or not self.text:
return
x = self.widget.winfo_rootx() + 20
y = self.widget.winfo_rooty() + 20
self.tipwindow = tw = tk.Toplevel(self.widget)
tw.wm_overrideredirect(True)
tw.wm_geometry(f"+{x}+{y}")
label = tk.Label(
tw,
text=self.text,
justify="left",
background="#ffffe0",
relief="solid",
borderwidth=1,
font=("Arial", 9),
padx=8,
pady=4
)
label.pack()
def hide(self, event=None):
if self.tipwindow:
self.tipwindow.destroy()
self.tipwindow = None
# Fenêtre principale
root = tk.Tk()
root.title("Analyse Réseau")
root.geometry("650x300")
root.resizable(False, False)
def open_switch_gui():
messagebox.showinfo(
"Analyse log Switch",
"L'analyse log switch n'est pas encore disponible."
)
# Fenêtre Firewall
def open_firewall_gui():
app = tk.Toplevel(root)
app.title("Analyse Configuration Firewall")
app.geometry("800x400")
app.resizable(False, False)
firewall_var = tk.StringVar()
input_var = tk.StringVar()
output_var = tk.StringVar()
excel_var = tk.BooleanVar()
def browse_input():
fw_type = firewall_var.get()
if fw_type == "":
messagebox.showerror("Erreur", "Veuillez d'abord sélectionner un type de firewall.")
return
if fw_type.lower() == "stormshield":
path = filedialog.askdirectory(title="Sélectionnez le dossier d'entrée", parent=app)
else:
path = filedialog.askopenfilename(title="Sélectionnez le fichier d'entrée", parent=app)
if path:
input_var.set(path)
def update_output_label(*args):
if firewall_var.get() == "":
output_label_var.set("Fichier de sortie :")
return
else :
fw = firewall_var.get().lower()
if output_var.get():
f_json = os.path.join(OUTPUT_DIR, f"{fw}_{output_var.get()}.json")
f_excel = os.path.join(OUTPUT_DIR, f"matrice_{fw}_{output_var.get()}.xlsx")
else:
dt = datetime.now().strftime("%Y%m%d")
f_json = os.path.join(OUTPUT_DIR, f"{fw}_{dt}.json")
f_excel = os.path.join(OUTPUT_DIR, f"matrice_{fw}_{dt}.xlsx")
if not excel_var.get():
output_label_var.set("Fichier de sortie :\n" + f_json)
else:
output_label_var.set("Fichiers de sortie :\n" + f_json + "\n" + f_excel)
app.update_idletasks()
def open_output_folder():
if sys.platform == "win32":
os.startfile(OUTPUT_DIR)
elif sys.platform == "darwin":
subprocess.run(["open", OUTPUT_DIR])
else:
subprocess.run(["xdg-open", OUTPUT_DIR])
def open_help():
if not os.path.exists(HELP_FILE_FW):
messagebox.showerror("Erreur", "Le fichier d'aide est introuvable.")
return
if sys.platform == "win32":
os.startfile(HELP_FILE_FW)
elif sys.platform == "darwin":
subprocess.run(["open", HELP_FILE_FW])
else:
subprocess.run(["xdg-open", HELP_FILE_FW])
def run_parser():
if not firewall_var.get():
messagebox.showerror("Erreur", "Veuillez sélectionner un type de firewall.")
return
if not input_var.get():
messagebox.showerror("Erreur", "Veuillez sélectionner un fichier ou dossier d'entrée.")
return
app.config(cursor="watch")
progress_bar = ttk.Progressbar(app, mode="indeterminate")
progress_bar.pack(pady=10, fill="x", padx=10)
progress_bar.start(10)
app.update_idletasks()
def process():
cmd = [
PYTHON_EXEC,
FIREWALL_MAIN,
firewall_var.get(),
input_var.get()
]
if output_var.get():
cmd.extend(["-o", output_var.get()])
if excel_var.get():
cmd.append("-m")
print("Commande exécutée :", " ".join(cmd))
print("Dossier courant (cwd) :", FIREWALL_DIR)
try:
subprocess.run(
cmd,
cwd=FIREWALL_DIR,
check=True
)
def on_success():
progress_bar.stop()
progress_bar.destroy()
app.config(cursor="")
messagebox.showinfo("Succès", "Traitement terminé avec succès.")
open_output_folder()
app.destroy()
app.after(0, on_success)
except subprocess.CalledProcessError as e:
def on_error():
progress_bar.stop()
progress_bar.destroy()
app.config(cursor="")
messagebox.showerror(
"Erreur",
f"Erreur lors de l'exécution du traitement.\n\n{e}"
)
app.after(0, on_error)
Thread(target=process, daemon=True).start()
header_frame = ttk.Frame(app)
header_frame.pack(fill="x", padx=10, pady=5)
ttk.Button(
header_frame,
text="Help",
width=6,
command=open_help
).pack(side="right")
ttk.Label(
header_frame,
text="Génération d'un fichier JSON au format normalisé YANG à partir des configurations d'un firewall",
font=("Arial", 8, "bold")
).pack(side="left")
ttk.Label(app, text="Type de firewall").pack(anchor="w", padx=10, pady=5)
ttk.Combobox(
app,
values=["paloalto", "stormshield", "forcepoint"],
textvariable=firewall_var,
state="readonly"
).pack(fill="x", padx=10)
input_label_var = tk.StringVar()
input_label_var.set("Fichier ou dossier de configuration source")
input_label_frame = ttk.Frame(app)
input_label_frame.pack(anchor="w", padx=5, pady=5)
info_label = ttk.Label(
input_label_frame,
text="",
cursor="hand2"
)
info_label.pack(side="right")
ttk.Label(
input_label_frame,
textvariable=input_label_var
).pack(side="left", padx=(5, 0))
ToolTip(
info_label,
"/!\\ Mettre le fichier/dossier de configurations\n"
"dans le dossier `/Parseurs_config_Firewall/src/input/` /!\\"
)
def update_input_label(*args):
fw_type = firewall_var.get().lower()
if fw_type == "stormshield":
input_label_var.set("Dossier de configuration source")
else:
input_label_var.set("Fichier de configuration source")
firewall_var.trace_add("write", update_input_label)
input_frame = ttk.Frame(app)
input_frame.pack(fill="x", padx=10)
ttk.Entry(input_frame, textvariable=input_var).pack(side="left", fill="x", expand=True)
ttk.Button(input_frame, text="Parcourir", command=browse_input).pack(side="right")
ttk.Label(app, text="Nom de sortie (optionnel)").pack(anchor="w", padx=10, pady=5)
ttk.Entry(app, textvariable=output_var).pack(fill="x", padx=10)
ttk.Checkbutton(
app,
text="Générer la matrice de flux en Excel",
variable=excel_var
).pack(anchor="w", padx=10, pady=10)
excel_var.set(True)
output_label_var = tk.StringVar()
ttk.Label(app, textvariable=output_label_var).pack(anchor="w", padx=10)
firewall_var.trace_add("write", update_output_label)
output_var.trace_add("write", update_output_label)
excel_var.trace_add("write", update_output_label)
update_output_label()
ttk.Button(
app,
text="Ouvrir le dossier de sortie",
command=open_output_folder
).pack(anchor="w", padx=10)
ttk.Button(
app,
text="Lancer le traitement",
command=run_parser
).pack(pady=15)
app.mainloop()
# Contenu fenêtre principale
ttk.Label(
root,
text="Analyse Réseau",
font=("Arial", 16, "bold")
).pack(pady=20)
ttk.Label(
root,
text="Sélectionnez le type d'analyse à effectuer :",
font=("Arial", 11)
).pack(pady=10)
ttk.Button(
root,
text="Analyse configuration Firewall",
width=30,
command=open_firewall_gui
).pack(pady=5)
ttk.Label(
root,
text="(Mise des données au format normalisé Yang dans un fichier JSON)" \
"\n + possibilité de générer une matrice de flux en Excel",
font=("Arial", 9, "italic"),
anchor="center",
justify="center"
).pack(pady=5)
ttk.Separator(root, orient="horizontal").pack(fill="x", pady=10)
ttk.Button(
root,
text="Analyse log Switch",
width=30,
command=open_switch_gui
).pack(pady=5)
ttk.Label(
root,
text="(Mise des données au format normalisé Yang dans un fichier JSON)" \
"\n + possibilité de générer un schéma réseau",
font=("Arial", 9, "italic"),
anchor="center",
justify="center"
).pack(pady=5)
root.mainloop()

20
help_Firewall.md Normal file
View File

@@ -0,0 +1,20 @@
# Analyse configuration Firewall
## Description
Cet outil permet de **récupérer les données des configurations de différents types de firewalls** (Palo Alto, Stormshield, Forcepoint) et de **convertir ces informations en un format JSON normalisé basé sur des modèles OpenConfig en YANG**.
Il fournit également la possibilité de générer une **matrice de flux au format Excel** pour visualiser les communications et règles de trafic dans linfrastructure.
## Utilisation
### Pré-requis
```bash
cd .\Parseurs_config_Firewall\
python -m venv .venv
.\.venv\Scripts\activate
pip install -r .\src\requierements.txt
```
- Mettre le/les fichier(s) et/ou dossier(s) de configurations dans le dossier `/Parseurs_config_Firewall/src/input/`
- Modifier le fichier `site.json` de données dans `/Parseurs_config_Firewall/src/data/`