1#
2#
3# Package d'analyse de fichiers de configuration JunOS
4#
5# Historique
6#   2004/03/22 : pda/jean : d�but de la conception
7#   2004/03/26 : pda/jean : fin de la r�daction
8#   2004/06/08 : pda/jean : changement de format du fichier de sortie
9#   2004/09/24 : pda/jean : nb d'arg variable pour les routes statiques
10#   2005/04/04 : pda      : ajout family address arp
11#   2005/06/01 : pda      : ajout family inet policer
12#   2006/05/26 : pda/jean : ajout des points de collecte de m�trologie
13#   2006/06/01 : pda/jean : ajout snmp
14#   2007/01/06 : pda      : ajout desc interface
15#   2009/12/21 : pda/jean : debut analyse junos switch
16#   2010/09/01 : pda/jean : analyse des directives voip
17#
18
19###############################################################################
20# Fonctions utilitaires
21###############################################################################
22
23proc juniper-init {} {
24    global juniper_masques
25    global juniper_where
26
27    # masques(24) {0xff 0xff 0xff 0x00 0x00 ... 0x00 }
28    # masques(25) {0xff 0xff 0xff 0x80 0x00 ... 0x00 }
29    # masques(64) {0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 ... 0x00 }
30
31    for {set i 1} {$i <= 128} {incr i} {
32	set juniper_masques($i) {}
33	set v 0
34	for {set j 0} {$j < 128} {incr j} {
35	    if {$j < $i} then {
36		set v [expr (($v << 1) | 1)]
37	    } else {
38		set v [expr (($v << 1) | 0)]
39	    }
40	    if {$j % 8 == 7} then {
41		set juniper_masques($i) [concat $juniper_masques($i) $v]
42		set v 0
43	    }
44	}
45    }
46
47    set juniper_where {}
48}
49
50proc juniper-warning {msg} {
51    global juniper_where
52
53    if {[llength $juniper_where] > 0} then {
54	puts -nonewline stderr "$juniper_where: "
55    }
56    puts stderr "$msg"
57}
58
59proc juniper-debug {msg} {
60    juniper-warning $msg
61}
62
63
64proc juniper-read-conf {fd} {
65    set conf ""
66    while {[gets $fd ligne] > -1} {
67	regsub { ## SECRET-DATA$} $ligne {} ligne
68	# remove comment lines
69	regsub {^#.*} $ligne {} ligne
70
71	# join bracketed statement running on consecutive lines
72	if { [regexp {^\s*\S+\s\[[^\]]*$} $ligne]} then {
73		while { ![eof $fd] && ![regexp {\]} $ligne]} {
74		    append ligne [gets $fd]
75		}
76	}
77
78	if {! [regexp {/\*.*\*/} $ligne]} then {
79	    regsub -all { \[ (.*) \];$} $ligne { { \1 } ;} ligne
80	    regsub -all {;$} $ligne { { } } ligne
81	    append conf "\n $ligne"
82	}
83    }
84    return $conf
85}
86
87#
88# Convertit une adresse au format Juniper (adr d'i/f + "/" + longueur pr�fixe)
89# en un CIDR de r�seau.
90#
91# Entr�e :
92#   - ifadr : adresse au format Juniper
93# Sortie :
94#   - valeur de retour : cidr de r�seau ou cha�ne vide en cas d'erreur
95#
96# Historique
97#   2004/03/25 : pda/jean : conception
98#   2004/03/26 : pda/jean : documentation
99#
100
101proc juniper-convert-ifadr-to-cidr {ifadr} {
102    global juniper_masques
103
104    if {! [regexp {^(.*)/(.*)$} $ifadr bidon adr preflen]} then {
105	juniper-warning "invalid interface address ($ifadr)"
106	return ""
107    }
108
109    set v6 [regexp ":" $adr]
110
111    if {$v6} then {
112	# Elimination des cas particuliers des adresses contenant
113	# un "::" situ� au d�but ou � la fin de l'adresse
114	regsub {^::} $adr {0::} adr
115	regsub {::$} $adr {::0} adr
116
117	# Traitement du cas particulier des adresses compatibles
118	# IPv4 : on les transforme en adresses en format IPv6
119	# (i.e. uniquement avec de l'hexa s�par� par des ":")
120	set l [split $adr ":"]
121
122	# cas particulier des adresses compatibles v4 (dernier = a.b.c.d)
123	set ip4 [split [lindex $l end] "."]
124	if {[llength $ip4] == 4} then {
125	    set l [lreplace $l end end]
126	    set p1 [format "%x" [expr [lindex $ip4 0] * 256 + [lindex $ip4 1]]]
127
128	    lappend l $p1
129	    set p2 [format "%x" [expr [lindex $ip4 2] * 256 + [lindex $ip4 3]]]
130	    lappend l $p2
131	}
132
133	# Traitement du cas des "::" dans l'adresse
134	set n [llength $l]
135	set lg0 [expr 8 - $n]
136	set posvide [lsearch $l {}]
137	if {$posvide >= 0} then {
138	     set l [concat [lrange $l 0 [expr $posvide - 1]] \
139				[lrange {0 0 0 0 0 0 0 0} 0 $lg0] \
140				[lrange $l [expr $posvide + 1] end] \
141			]
142	}
143	# A ce stade, l est une liste de 8 valeurs sur 16 bits en hexa (sans 0x)
144
145	# Transformer chaque �l�ment en octet (en d�cimal)
146	set nl {}
147	foreach e $l {
148	    lappend nl [expr ((0x$e >> 8) & 0xff)]
149	    lappend nl [expr (0x$e & 0xff)]
150	}
151
152	# A ce stade, nl est une liste de 16 octets en d�cimal
153	set m $juniper_masques($preflen)
154	set na {}
155	for {set i 0} {$i < 16} {incr i} {
156	    lappend na [expr [lindex $nl $i] & [lindex $m $i]]
157	}
158
159	# Reconstituer l'adresse IPv6
160	set l {}
161	for {set i 0} {$i < 8} {incr i} {
162	    set o1 [lindex $na [expr $i * 2]]
163	    set o2 [lindex $na [expr ($i * 2) + 1]]
164	    lappend l [format "%x" [expr ($o1 << 8) + $o2]]
165	}
166	set a [join $l ":"]
167
168	# supprimer les 0 finaux
169	regsub -expanded {(:0)+$} $a {::} a
170
171	set na $a
172    } else {
173	#
174	# IPv4
175	#
176	set a [split $adr "."]
177	set m $juniper_masques($preflen)
178	set na {}
179	for {set i 0} {$i < 4} {incr i} {
180	    lappend na [expr [lindex $a $i] & [lindex $m $i]]
181	}
182	set na [join $na "."]
183    }
184
185    return "$na/$preflen"
186}
187
188#
189# Teste l'appartenance d'une adresse IP (v4 ou v6) � un r�seau
190#
191# Entr�e :
192#   - adr : adresse � tester
193#   - cidr : cidr du r�seau
194# Sortie :
195#   - valeur de retour : -1 (erreur), 1 (appartenance) ou 0 (pas d'appartenance)
196#
197# Historique
198#   2004/03/25 : pda/jean : conception
199#   2004/03/26 : pda/jean : documentation
200#
201
202proc juniper-match-network {adr cidr} {
203    if {! [regexp {^(.*)/(.*)$} $cidr bidon bidon2 preflen]} then {
204	juniper-warning "invalid network address ($cidr)"
205	set r -1
206    } else {
207	set na [juniper-convert-ifadr-to-cidr "$adr/$preflen"]
208	set r [string equal $na $cidr]
209    }
210    return $r
211}
212
213###############################################################################
214# Analyse du fichier de configuration
215###############################################################################
216
217#
218# Entr�e :
219#   - libdir : r�pertoire contenant les greffons d'analyse
220#   - model : mod�le de l'�quipement (ex: M20)
221#   - fdin : descripteur de fichier en entr�e
222#   - fdout : descripteur de fichier pour la g�n�ration
223#   - conf : { interfaces ... system ... etc }
224#   - eq : <eqname>
225# Remplit :
226#   - tab(eq)	{<eqname> ... <eqname>}
227#
228# Historique
229#   2004/03/23 : pda/jean : conception
230#   2004/06/08 : pda/jean : ajout de model
231#   2008/07/07 : pda/jean : ajout param�tre libdir
232#   2009/12/21 : pda/jean : debut analyse junos switch
233#
234
235proc juniper-parse {libdir model fdin fdout tab eq} {
236    upvar $tab t
237
238    array set kwtab {
239	version				{2	NOP}
240	groups				{1	NOP}
241	apply-groups			{2	NOP}
242	apply-groups-except		{2	NOP}
243	interfaces			{1	juniper-parse-interfaces}
244	snmp				{1	juniper-parse-snmp}
245	routing-options			{1	juniper-parse-routing-options}
246	ethernet-switching-options	{1	juniper-parse-ethernet-swopt}
247	vlans				{1	juniper-parse-vlans}
248	bridge-domains			{1	juniper-parse-bridge-domains}
249	protocols			{1	juniper-parse-protocols}
250	*				{1	NOP}
251
252    }
253
254    set conf [juniper-read-conf $fdin]
255
256    # le nom de l'�quipement en cours d'analyse
257    lappend t(eq) $eq
258
259    set t(eq!$eq!if!disabled) {}
260    set t(eq!$eq!brcandidate) {}
261    set t(eq!$eq!brdomlist) {}
262    set t(eq!$eq!ranges) {}
263    set t(eq!$eq!voip!if!list) {}
264
265    set error [juniper-parse-list kwtab $conf t "eq!$eq"]
266
267    if {! $error} then {
268	set error [juniper-post-process $model $fdout $eq t]
269    }
270
271    return $error
272}
273
274#
275# Analyse un extrait de conf JunOS
276#
277# Entr�e :
278#   - kwtab : tableau des mots-clefs autoris�s dans la fonction, sous la
279#	forme kwtab(<kw>) { <nb args> <fct d'analyse> }
280#		si <nb-args> n'est pas un entier, il s'agit d'une fonction
281#		que l'on appelle, et qui doit retourner le nb d'arguments
282#   - tab : tableau contenant les informations r�sultant de l'analyse
283#   - conf : extrait de conf
284#   - idx : index dans le tableau tab
285#   - variable globale debug : affiche tous les mots-clefs en cours d'analyse
286# Sortie :
287#   - valeur de retour : 1 si erreur, 0 sinon
288#
289# Historique
290#   2004/03/25 : pda/jean : conception (ouh la la !)
291#
292
293proc juniper-parse-list {kwtab conf tab idx} {
294    global juniper_where
295    global debug
296    upvar $kwtab k
297    upvar $tab t
298
299    set inactive 0
300    set error 0
301    while {[llength $conf] > 0} {
302	set kw [lindex $conf 0]
303
304	if {$debug & 0x01} then {
305	    juniper-debug "kw = <$kw>"
306	}
307
308	if {[string equal $kw "inactive:"]} then {
309	    set inactive 1
310	    set last 0
311	} else {
312	    if {[info exists k($kw)]} then {
313		set l $k($kw)
314	    } else {
315		set l $k(*)
316	    }
317	    set last [lindex $l 0]
318	    if {! [regexp {^[0-9]+$} $last]} then {
319		set fct $last
320		if {[catch [list $fct $conf t $idx] last]} then {
321		    juniper-warning "$idx: error while fetching arg count ($kw)"
322		    set last end
323		    set inactive 1
324		}
325	    }
326	    if {! $inactive} then {
327		set fct  [lindex $l 1]
328		if {$debug & 0x04} then {
329		    juniper-debug "kw = <$kw>, fct = <$fct>"
330		}
331		if {$debug & 0x08} then {
332		    juniper-debug "kw = <$kw>, fct = <$fct>, conf 0/1 = <[lindex $conf 0]><[lindex $conf 1]>"
333		}
334		switch $fct {
335		    NOP {
336			set error 0
337		    }
338		    ERROR {
339			juniper-warning "$idx: unrecognized keyword ($kw)"
340			set error 1
341		    }
342		    default {
343			lappend juniper_where $kw
344			set error [$fct $conf t $idx]
345			set juniper_where [lreplace $juniper_where end end]
346		    }
347		}
348
349		if {$error} then {
350		    break
351		}
352	    }
353	    set inactive 0
354	}
355	set conf [lreplace $conf 0 $last]
356    }
357    return $error
358}
359
360
361#
362# Entr�e :
363#   - conf = <ifname> { <parm> } <ifname> { <parm> } ...
364#   - idx = eq!<eqname>
365# Remplit
366#   - tab(eq!<nom eq>!if) {<ifname> ... <ifname>}
367#
368# Historique
369#   2004/03/23 : pda/jean : conception
370#   2005/05/26 : pda      : ignorer l'i/f tap
371#
372
373proc juniper-parse-interfaces {conf tab idx} {
374    upvar $tab t
375
376    array set kwtab {
377	fxp0		{1	NOP}
378	fxp1		{1	NOP}
379	lo0		{1	NOP}
380	tap		{1	NOP}
381	traceoptions	{1	NOP}
382	apply-groups	{2	NOP}
383	apply-groups-except	{2      NOP}
384	interface-range	{2	juniper-parse-if-range}
385	*		{1	juniper-parse-if}
386    }
387
388    return [juniper-parse-list kwtab [lindex $conf 1] t "$idx"]
389}
390
391
392#
393# Entr�e :
394#   - idx = eq!<eqname> ou eq!<eqname>!ifrange!<nom>
395#   - conf = {ge-0/0/0 { description <desc> unit <nb> { ... }} ... }
396#	ou {<range> { description <desc> unit <nb> { ... }} ... } si range
397# Remplit :
398#   - t(eq!<eqname>!ranges) {<range> ... <range>}
399#   - t(eq!<eqname>!if) {<ifname> ... <ifname>}
400#
401# Historique :
402#   2009/12/21 : pda/jean : debut analyse junos switch
403#   2010/03/24 : pda      : interfaces d�sactiv�es
404#
405
406proc juniper-parse-if {conf tab idx} {
407    upvar $tab t
408
409    array set kwtab {
410	mtu			{2	NOP}
411	description		{2	juniper-parse-if-descr}
412	disable			{1	juniper-parse-if-disable}
413	native-vlan-id		{2	juniper-parse-if-nativevlan}
414	unit			{2	juniper-parse-if-unit}
415	gigether-options	{1	juniper-parse-if-gigopt}
416	ether-options		{1	juniper-parse-if-gigopt}
417	aggregated-ether-options {1	NOP}
418	flexible-vlan-tagging   {1	NOP}
419	encapsulation		{2	NOP}
420	vlan-tagging		{1	juniper-parse-if-vlan-tagging}
421	member-range		{4	juniper-parse-member-range}
422	member			{2	juniper-parse-member}
423	traceoptions		{1	NOP}
424	apply-groups		{2	NOP}
425	apply-groups-except     {2      NOP}
426	*			{2	ERROR}
427    }
428
429    # ifname peut �tre un nom d'interface ou d'intervalle (range)
430    set ifname [lindex $conf 0]
431    set ifparm [lindex $conf 1]
432
433    set t(current!iface) $ifname
434
435    if {[info exists t(in-range)]} then {
436	lappend t($idx!ranges) $ifname
437	set idxin "$idx!range!$ifname"
438    } else {
439	# on diff�re l'ajout de l'interface dans la liste
440	# des interfaces apr�s l'analyse, pour le cas o�
441	# l'interface serait d�sactiv�e.
442	set idxin "$idx!if!$ifname"
443    }
444
445    set error [juniper-parse-list kwtab $ifparm t $idxin]
446
447    # ajout de l'interface dans la liste des interfaces
448    # activ�es ou d�sactiv�es
449    if {! [info exists t(in-range)]} then {
450	if {! [info exists t($idx!if!$ifname!disable)]} then {
451	    lappend t($idx!if) $ifname
452	} else {
453	    lappend t($idx!if!disabled) $ifname
454	}
455    }
456
457    unset t(current!iface)
458
459    return $error
460}
461
462#
463# Entr�e :
464#   - idx = eq!<eqname>
465# Remplit :
466#   - <plein de choses>
467#
468# Historique :
469#   2009/12/21 : pda/jean : conception
470#
471
472proc juniper-parse-if-range {conf tab idx} {
473    upvar $tab t
474
475    set t(in-range) "n'importe quoi"
476    set r [juniper-parse-if [lreplace $conf 0 0] t $idx]
477    unset t(in-range)
478
479    return $r
480}
481
482#
483# Entr�e :
484#   - idx = eq!<eqname>!range!<range>
485#   - conf = { member-range <if1> to <if2> ... }
486# Remplit :
487#   - t(eq!<eqname>!range!<range>!members) {{<ifstart> <ifend>} ...}
488#
489# Historique :
490#   2009/12/21 : pda/jean : conception
491#
492
493proc juniper-parse-member-range {conf tab idx} {
494    upvar $tab t
495
496    set if1 [lindex $conf 1]
497    set if2 [lindex $conf 3]
498    lappend t($idx!members) [list $if1 $if2]
499    return 0
500}
501
502#
503# Entr�e :
504#   - idx = eq!<eqname>!range!<range>
505#   - conf = { member <if> ... }
506# Remplit :
507#   - t(eq!<eqname>!range!<range>!members) {{<if> <if>} ...}
508#
509# Historique :
510#   2009/12/21 : pda/jean : conception
511#
512
513proc juniper-parse-member {conf tab idx} {
514    upvar $tab t
515
516    set if [lindex $conf 1]
517    lappend t($idx!members) [list $if $if]
518    return 0
519}
520
521#
522# Entr�e :
523#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
524# Remplit :
525#   tab(eq!<eqname>!if!<ifname>!link!name) <linkname>
526#   tab(eq!<nom eq>!if!<ifname>!link!stat) <statname> ou vide
527#   tab(eq!<nom eq>!if!<ifname>!link!desc) <desc>
528#
529# Historique :
530#   2004/03/23 : pda/jean : conception
531#   2006/05/23 : pda/jean : ajout de stat
532#   2007/01/06 : pda      : ajout de desc
533#
534
535proc juniper-parse-if-descr {conf tab idx} {
536    upvar $tab t
537
538    set line [lindex $conf 1]
539
540    if {[parse-desc $line linkname statname descname msg]} then {
541	if {[string equal $linkname ""]} then {
542	    juniper-warning "$idx: no link name found ($line)"
543	    set error 1
544	} else {
545	    set t($idx!link!name) $linkname
546	    set t($idx!link!stat) $statname
547	    set t($idx!link!desc) $descname
548	    set error 0
549	}
550    } else {
551	juniper-warning "$idx: $msg ($line)"
552	set error 1
553    }
554
555    return $error
556}
557
558#
559# Entr�e :
560#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
561# Remplit :
562#   tab(eq!<eqname>!if!<ifname>!disable) 1
563#
564# Historique :
565#   2010/03/24 : pda      : conception
566#
567
568proc juniper-parse-if-disable {conf tab idx} {
569    upvar $tab t
570
571    set t($idx!disable) yes
572    return 0
573}
574
575#
576# Entr�e :
577#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
578# Remplit :
579#
580
581proc juniper-parse-if-unit {conf tab idx} {
582    upvar $tab t
583
584    array set kwtab {
585	description	{2	juniper-parse-unit-descr}
586	vlan-id		{2	juniper-parse-vlan-id}
587	family		{2	juniper-parse-family}
588	disable		{1	juniper-parse-unit-disable}
589	encapsulation	{2	juniper-parse-unit-encap}
590	tunnel		{1	NOP}
591	apply-groups	{2	NOP}
592	apply-groups-except	{2      NOP}
593	traceoptions	{1	NOP}
594	*		{2	ERROR}
595    }
596
597    set unitnb   [lindex $conf 1]
598    set unitparm [lindex $conf 2]
599
600    set t(current!unitnb) $unitnb
601    set t($idx!vlan!$unitnb!stat) ""
602    set error [juniper-parse-list kwtab $unitparm t "$idx"]
603    unset t(current!unitnb)
604
605# XXX
606# This code has been deactivated since some interface networks
607# may be emtpy on JunOS routers (eg interface connected to a
608# bridge domain) without being a switch.
609#
610#    #
611#    # Cas particulier : s'il n'y a aucun network, l'interface
612#    # est consid�r�e comme participant � un JunOS switch.
613#    # Ce cas est n�cessaire pour g�rer la d�sactivation de
614#    # port via l'interface Web.
615#    #
616#
617#    if {! [info exists t($idx!vlan!$unitnb!networks)]} then {
618#	set t($idx!l2switch) on
619#    }
620
621    return $error
622}
623
624#
625# Entr�e :
626#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
627# Remplit :
628#   tab(eq!<eqname>!if!<ifname>!disable) 1
629#
630# Historique :
631#   2010/03/24 : pda      : conception
632#
633
634proc juniper-parse-unit-disable {conf tab idx} {
635    upvar $tab t
636
637    set unit $t(current!unitnb)
638    set t($idx!vlan!$unit!disable) yes
639
640    return 0
641}
642
643
644#
645# Entr�e :
646#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
647# Remplit :
648#   nothing
649#
650# Historique :
651#   2010/03/24 : pda      : conception
652#
653
654proc juniper-parse-unit-encap {conf tab idx} {
655    upvar $tab t
656
657    # placeholder for future
658    return 0
659}
660
661
662#
663# Entr�e :
664#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
665#   - tab(current!unitnb) = <unit number>
666# Remplit :
667#   tab(eq!<nom eq>!if!<ifname>!vlan!<vlan-id>!stat) <statname> ou vide
668#
669# Historique :
670#   2006/05/26 : pda/jean : conception
671#
672
673proc juniper-parse-unit-descr {conf tab idx} {
674    upvar $tab t
675
676    set unitnb $t(current!unitnb)
677    set line [lindex $conf 1]
678
679    if {[parse-desc $line linkname statname descname msg]} then {
680	#
681	# 1) linkname peut contenir n'importe quoi (compatibilit� avec
682	#    l'ancienne syntaxe), donc on l'ignore
683	# 2) on fait toujours l'approximation : num�ro d'unit� = no de vlan
684	# 3) m�me s'il n'y a pas de d�finition d'un point de collecte
685	#    de m�trologie (statname = cha�ne vide), on remplit
686	#    le tableau
687	#
688	set t($idx!vlan!$unitnb!stat) $statname
689	set error 0
690    } else {
691	juniper-warning "$idx: $msg ($line)"
692	set error 1
693    }
694
695    return $error
696}
697
698
699#
700# Entr�e :
701#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
702#   - tab(current!unitnb) = <unit number>
703# Remplit :
704#   tab(eq!<eqname>!if!<ifname>!vlans) {<vlan-id> ...}
705#
706# Historique :
707#   2004/03/23 : pda/jean : conception
708#
709
710proc juniper-parse-vlan-id {conf tab idx} {
711    upvar $tab t
712
713    set unitnb $t(current!unitnb)
714    set parm [lindex $conf 1]
715
716    # approximation : num�ro d'unit� = no de vlan
717    if {$unitnb != $parm} then {
718	juniper-warning "$idx: vlan-id $parm does not match unit $unitnb"
719	return 1
720    }
721
722    lappend t($idx!vlans) $unitnb
723    return 0
724}
725
726#
727# Entr�e :
728#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
729#   - tab(current!unitnb) = <unit number>
730# Remplit :
731#   tab(eq!<eqname>!if!<ifname>!vlan!<unitnb>!adr) {<adr46> ...}
732#
733#   tab(eq!<eqname>!if!<ifname>!vlan!<unitnb>!networks) {<cidr46> ...}
734#   tab(eq!<eqname>!if!<ifname>!vlan!<unitnb>!net!<cidr46>) { <adr46> [<poidsvrrp> <virtadr>]}
735#
736
737proc juniper-parse-family {conf tab idx} {
738    upvar $tab t
739
740    set fam [lindex $conf 1]
741    switch $fam {
742	inet -
743	inet6 {
744	    array set kwtab {
745		targeted-broadcast	{1	NOP}
746		filter			{1	NOP}
747		sampling		{1	NOP}
748		policer			{1	NOP}
749		address			{2	juniper-parse-if-address}
750		apply-groups		{2	NOP}
751		apply-groups-except	{2      NOP}
752		traceoptions		{1	NOP}
753		*			{2	NOP}
754	    }
755	    set unitnb $t(current!unitnb)
756	    set parm [lindex $conf 2]
757	    set error [juniper-parse-list kwtab $parm t "$idx!vlan!$unitnb"]
758	}
759	mpls -
760	iso {
761	    set error 0
762	}
763	ethernet-switching {
764	    array set kwtab {
765		interface-mode	{2	juniper-parse-l2switch-portmode}
766		port-mode	{2	juniper-parse-l2switch-portmode}
767		vlan		{1	juniper-parse-l2switch-vlan}
768		native-vlan-id	{2	juniper-parse-l2switch-nativevlan}
769		traceoptions	{1	NOP}
770		*		{2	NOP}
771	    }
772	    set t($idx!l2switch) on
773	    set parm [lindex $conf 2]
774	    set error [juniper-parse-list kwtab $parm t $idx]
775	}
776	bridge {
777	    array set kwtab {
778		filter		{1	NOP}
779		interface-mode	{2	juniper-parse-fbridge-ifmode}
780		vlan-id		{2	juniper-parse-fbridge-vlanid}
781		vlan-id-list	{2	juniper-parse-fbridge-vlanidlist}
782		*		{2	NOP}
783	    }
784	    set t($idx!link!allowedvlans) {}
785	    set parm [lindex $conf 2]
786	    set error [juniper-parse-list kwtab $parm t $idx]
787	    # append this interface to the list of candidates to a bridge domain
788	    set eq $t(eq)
789	    lappend t(eq!$eq!brcandidate) $t(current!iface)
790	}
791	default {
792	    juniper-warning "$idx: family '$fam' not supported"
793	    set error 1
794	}
795    }
796    return $error
797}
798
799#
800# Entr�e :
801#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
802#
803# Historique
804#   2009/12/22 : pda/jean : conception
805#
806
807proc juniper-parse-l2switch-portmode {conf tab idx} {
808    upvar $tab t
809
810    set error 0
811    set mode [lindex $conf 1]
812    switch $mode {
813	trunk {
814	    set t($idx!link!type) "trunk"
815	}
816	access {
817	    set t($idx!link!type) "ether"
818	}
819	default {
820	    juniper-warning "$idx: port-mode '$mode' not supported"
821	    set error 1
822	}
823    }
824    return $error
825}
826
827#
828# Entr�e :
829#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
830#
831# Historique
832#   2009/12/22 : pda/jean : conception
833#
834
835proc juniper-parse-l2switch-vlan {conf tab idx} {
836    upvar $tab t
837
838    array set kwtab {
839	members		{3	juniper-parse-l2switch-vlan-members}
840	apply-groups	{2	NOP}
841	apply-groups-except	{2      NOP}
842	traceoptions	{1	NOP}
843	*		{1	ERROR}
844    }
845    set error [juniper-parse-list kwtab [lindex $conf 1] t "$idx"]
846    return $error
847}
848
849#
850# Entr�e :
851#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
852#
853# Historique
854#   2009/12/22 : pda/jean : conception
855#
856
857proc juniper-parse-l2switch-vlan-members {conf tab idx} {
858    upvar $tab t
859
860    set vlans [lindex $conf 1]
861    foreach v $vlans {
862	if {[regexp {^(\d+)-(\d+)$} $v bidon min max]} then {
863	    set l [list $min $max]
864	} else {
865	    set l [list $v $v]
866	}
867	lappend t($idx!link!allowedvlans) $l
868    }
869    return 0
870}
871
872#
873# Entrée :
874#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
875#   - tab(current!unitnb) = <unit number>
876# Remplit :
877#   tab(eq!<eqname>!if!<ifname>!link!allowedvlans) {<vlan-id|vlan-name> ...}
878#   tab(eq!<eqname>!if!<ifname>!native-vlan) <vlan-id|vlan-name>
879#
880# Historique
881#   2009/12/22 : pda/jean : conception
882#   2010/08/31 : pda/jean : gestion effective du vlan natif
883#
884
885proc juniper-parse-l2switch-nativevlan {conf tab idx} {
886    upvar $tab t
887
888    set vlan [lindex $conf 1]
889    lappend t($idx!link!allowedvlans) [list $vlan $vlan]
890    set t($idx!native-vlan) $vlan
891    return 0
892}
893
894#
895# Entr�e :
896#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
897# Remplit :
898#   tab(eq!<eqname>!if!<ifname>!native-vlan) <vlan-id|vlan-name>
899#
900# Apparently used only for bridge family
901#
902# Historique
903#   2012/07/03 : pda/jean : conception
904#
905
906proc juniper-parse-if-nativevlan {conf tab idx} {
907    upvar $tab t
908
909    set vlan [lindex $conf 1]
910    set t($idx!native-vlan) $vlan
911    return 0
912}
913
914#
915# Entr�e :
916#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
917#   - tab(current!unitnb) = <unit number>
918# Remplit :
919#   tab(eq!<eqname>!if!<ifname>!link!type) trunk|ether
920#
921# Historique
922#   2012/07/03 : pda/jean : conception
923#
924
925proc juniper-parse-fbridge-ifmode {conf tab idx} {
926    upvar $tab t
927
928    set error 0
929    set mode [lindex $conf 1]
930    switch $mode {
931	trunk {
932	    set t($idx!link!type) "trunk"
933	}
934	access {
935	    set t($idx!link!type) "ether"
936	}
937	default {
938	    juniper-warning "$idx: interface-mode '$mode' not supported"
939	    set error 1
940	}
941    }
942    return $error
943}
944
945#
946# Entr�e :
947#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
948# Remplit :
949#   tab(eq!<eqname>!if!<ifname>!link!allowedvlans) {id id}
950#
951# Historique
952#   2012/07/03 : pda/jean : conception
953#
954
955proc juniper-parse-fbridge-vlanid {conf tab idx} {
956    upvar $tab t
957
958    set vlan [lindex $conf 1]
959    lappend t($idx!link!allowedvlans) [list $vlan $vlan]
960    return 0
961}
962
963#
964# Entr�e :
965#   - idx = eq!<eqname>!if!<ifname> ou eq!<eqname>!range!<range>
966# Remplit :
967#   tab(eq!<eqname>!if!<ifname>!bridge!<vlanid>!mode) trunk (for all $vlanid)
968#   tab(eq!<eqname>!if!<ifname>!link!allowed-vlans) {{ min max } ...}
969#		(except native-vlan)
970#
971# Historique
972#   2012/07/03 : pda/jean : conception
973#
974
975proc juniper-parse-fbridge-vlanidlist {conf tab idx} {
976    upvar $tab t
977
978    # native vlan (if any) will be checked during post processing
979    # t(eq!<eq>!if!<ifname>!nativevlan) <vland-id>
980
981    set vlans [lindex $conf 1]
982    foreach v $vlans {
983	if {[regexp {^(\d+)-(\d+)$} $v bidon min max]} then {
984	    set l [list $min $max]
985	} else {
986	    set l [list $v $v]
987	}
988	lappend t($idx!link!allowedvlans) $l
989    }
990    return 0
991}
992
993#
994# Entr�e :
995#   - idx = eq!<eqname>!if!<ifname>!unit!<unitnb>
996# Remplit :
997#   tab(eq!<eqname>!if!<ifname>!vlan!<unitnb>!networks) {<cidr46> ...}
998#   tab(eq!<eqname>!if!<ifname>!vlan!<unitnb>!net!<cidr46>) <adr46>
999#   tab(eq!<eqname>!if!<ifname>!vlan!<unitnb>!net!<cidr46>!preflen) <preflen>
1000#
1001
1002proc juniper-parse-if-address {conf tab idx} {
1003    upvar $tab t
1004
1005    array set kwtab {
1006	vrrp-group	    {2	juniper-parse-vrrp}
1007	vrrp-inet6-group    {2	juniper-parse-vrrp}
1008	arp		    {4	NOP}
1009	destination	    {2	NOP}
1010	apply-groups	    {2	NOP}
1011	apply-groups-except	{2      NOP}
1012	traceoptions	    {1	NOP}
1013	*		    {2	ERROR}
1014    }
1015
1016    set parm [lindex $conf 1]
1017    if {! [regexp {^(.*)/(.*)$} $parm bidon ifadr preflen]} then {
1018	juniper-warning "$idx: invalid address ($parm)"
1019    }
1020    set cidr [juniper-convert-ifadr-to-cidr $parm]
1021    if {[string equal $cidr ""]} then {
1022	set error 1
1023    } else {
1024	lappend t($idx!networks) $cidr
1025	set idx "$idx!net!$cidr"
1026	set t($idx) $ifadr
1027	set t($idx!preflen) $preflen
1028	set error [juniper-parse-list kwtab [lindex $conf 2] t "$idx"]
1029    }
1030
1031    return $error
1032}
1033
1034#
1035# Entr�e :
1036#   - idx = eq!<eqname>!if!<ifname>!net!<cidr>
1037# Remplit :
1038#   - rien
1039#
1040# Historique :
1041#   2004/03/23 : pda/jean : conception
1042#
1043
1044proc juniper-parse-vrrp {conf tab idx} {
1045    upvar $tab t
1046
1047    array set kwtab {
1048	virtual-address		{2	juniper-parse-vrrp-vadr}
1049	priority		{2	juniper-parse-vrrp-prio}
1050	virtual-inet6-address	{2	juniper-parse-vrrp-vadr}
1051	accept-data		{1	NOP}
1052	apply-groups	    	{2	NOP}
1053	apply-groups-except	{2      NOP}
1054	traceoptions	    	{1	NOP}
1055	*			{2	NOP}
1056    }
1057
1058    return [juniper-parse-list kwtab [lindex $conf 2] t $idx]
1059}
1060
1061#
1062# Entr�e :
1063#   - idx = eq!<eqname>!if!<ifname>!net!<cidr>
1064# Remplit :
1065#   - tab(eq!<eqname>!if!<ifname>!net!<cidr>!vrrp!virtual) <adrvirt>
1066#
1067# Historique :
1068#   2004/03/25 : pda/jean : conception
1069#
1070
1071proc juniper-parse-vrrp-vadr {conf tab idx} {
1072    upvar $tab t
1073
1074    set t($idx!vrrp!virtual) [lindex $conf 1]
1075    return 0
1076}
1077
1078#
1079# Entr�e :
1080#   - idx = eq!<eqname>!if!<ifname>!net!<cidr>
1081# Remplit :
1082#   - tab(eq!<eqname>!if!<ifname>!net!<cidr>!vrrp!priority) <prio>
1083#
1084# Historique :
1085#   2004/03/25 : pda/jean : conception
1086#
1087
1088proc juniper-parse-vrrp-prio {conf tab idx} {
1089    upvar $tab t
1090
1091    set t($idx!vrrp!priority) [lindex $conf 1]
1092    return 0
1093}
1094
1095#
1096# Entr�e :
1097#   - idx = eq!<eqname>!if!<ifname>
1098# Remplit :
1099#   - rien
1100#
1101# Historique :
1102#   2004/03/23 : pda/jean : conception
1103#   2010/06/17 : pda      : ajout link-mode
1104#   2010/09/?? : saillard : ajout no-auto-nego + no-flow-control
1105#
1106
1107proc juniper-parse-if-gigopt {conf tab idx} {
1108    upvar $tab t
1109
1110    array set kwtab {
1111	802.3ad			{2	juniper-parse-802-3ad}
1112	link-mode		{2	NOP}
1113	speed			{1	NOP}
1114        auto-negotiation	{1	NOP}
1115        no-auto-negotiation	{1	NOP}
1116        no-flow-control		{1	NOP}
1117	apply-groups	    	{2	NOP}
1118	apply-groups-except	{2      NOP}
1119	traceoptions	    	{1	NOP}
1120	*			{2	ERROR}
1121    }
1122    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1123}
1124
1125#
1126# Entr�e :
1127#   - idx = eq!<eqname>!if!<ifname>
1128# Remplit :
1129#   - tab(eq!<eqname>!if!<ifname>!link!type) aggregate
1130#   - tab(eq!<eqname>!if!<ifname>!link!ifname) <ifname2>
1131#
1132# Historique :
1133#   2004/03/23 : pda/jean : conception
1134#
1135
1136proc juniper-parse-802-3ad {conf tab idx} {
1137    upvar $tab t
1138
1139    set ifname [lindex $conf 1]
1140    set t($idx!link!type) "aggregate"
1141    set t($idx!link!ifname) $ifname
1142
1143    return 0
1144}
1145
1146#
1147# Entr�e :
1148#   - idx = eq!<eqname>!if!<ifname>
1149# Remplit :
1150#   - tab(eq!<eqname>!if!<ifname>!link!type) trunk
1151#
1152# Historique :
1153#   2004/03/23 : pda/jean : conception
1154#
1155
1156proc juniper-parse-if-vlan-tagging {conf tab idx} {
1157    upvar $tab t
1158
1159    set t($idx!link!type) "trunk"
1160    return 0
1161}
1162
1163#
1164# Entr�e :
1165#   - idx = eq!<eqname>
1166# Remplit :
1167#   - rien
1168#
1169# Historique :
1170#   2004/03/25 : pda/jean : conception
1171#
1172
1173proc juniper-parse-routing-options {conf tab idx} {
1174    upvar $tab t
1175
1176    array set kwtab {
1177	rib			{2	NOP}
1178	static			{1	juniper-parse-static-routes}
1179	autonomous-system	{2	NOP}
1180	apply-groups	    	{2	NOP}
1181	apply-groups-except     {2      NOP}
1182	traceoptions	    	{1	NOP}
1183	*			{1	NOP}
1184    }
1185
1186    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1187}
1188
1189#
1190# Entr�e :
1191#   - idx = eq!<eqname>
1192# Remplit :
1193#   - rien
1194#
1195# Historique :
1196#   2004/03/25 : pda/jean : conception
1197#   2010/06/21 : pda      : ignorer rib-group
1198#
1199
1200proc juniper-parse-static-routes {conf tab idx} {
1201    upvar $tab t
1202
1203    array set kwtab {
1204	route		{juniper-parse-count-route juniper-parse-route-entry}
1205	rib-group	{2	NOP}
1206	apply-groups	{2	NOP}
1207	apply-groups-except	{2      NOP}
1208	traceoptions	{1	NOP}
1209	*		{1	ERROR}
1210    }
1211
1212    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1213}
1214
1215#
1216# Entr�e :
1217#   - idx = eq!<eqname>
1218# Remplit :
1219#   - tab(eq!<eqname>!static!gw) {<gwadr46> ... }
1220#   - tab(eq!<eqname>!static!<gwadr46>) {<cidr46> ... }
1221#
1222# Historique :
1223#   2004/03/25 : pda/jean : conception
1224#   2004/03/26 : pda/jean : inversion des donn�es dans le tableau
1225#   2004/09/21 : pda/jean : nb d'arguments variable pour les entr�es statiques
1226#
1227
1228# cette fonction ne fait que retourner le nombre d'arguments
1229proc juniper-parse-count-route {conf tab idx} {
1230    upvar $tab t
1231
1232    set n 2
1233    if {[string equal [lindex $conf 2] "next-hop"]} then {
1234	set n 4
1235    }
1236    return $n
1237}
1238
1239
1240proc juniper-parse-route-entry {conf tab idx} {
1241    upvar $tab t
1242
1243    set cidr  [lindex $conf 1]
1244
1245    if {[string equal [lindex $conf 2] "next-hop"]} then {
1246	set gwadr [lindex $conf 3]
1247	if {[llength $gwadr] > 1} then {
1248	    # XXX : il y a plusieurs passerelles pour cette route
1249	    # on ne conserve que la premi�re
1250	    set gwadr [lindex $gwadr 0]
1251	}
1252
1253	if {! [info exists t($idx!static!$gwadr)]} then {
1254	    lappend t($idx!static!gw) $gwadr
1255	}
1256	lappend t($idx!static!$gwadr) $cidr
1257    }
1258
1259    return 0
1260}
1261
1262
1263
1264#
1265# Entr�e :
1266#   - idx = eq!<eqname>
1267# Remplit :
1268#   - rien
1269#
1270# Historique :
1271#   2006/06/01 : pda/jean : conception
1272#   2008/05/06 : pda      : ajout location
1273#
1274
1275proc juniper-parse-snmp {conf tab idx} {
1276    upvar $tab t
1277
1278    array set kwtab {
1279	trap-options	        {1	NOP}
1280	trap-group	        {2	NOP}
1281	community	        {2	juniper-parse-snmp-community}
1282	location	        {2	juniper-parse-snmp-location}
1283	apply-groups	        {2	NOP}
1284	apply-groups-except	{2      NOP}
1285	traceoptions	        {1	NOP}
1286	routing-instance-access	{1	NOP}
1287	*		        {1	ERROR}
1288    }
1289
1290    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1291}
1292
1293#
1294# Entr�e :
1295#   - idx = eq!<eqname>
1296# Remplit :
1297#   - tab(eq!<eqname>!snmp) {<community string> ... }
1298#
1299# Historique :
1300#   2006/06/01 : pda/jean : conception
1301#
1302
1303proc juniper-parse-snmp-community {conf tab idx} {
1304    upvar $tab t
1305
1306    set comm  [lindex $conf 1]
1307    lappend t($idx!snmp) $comm
1308    return 0
1309}
1310
1311#
1312# Entr�e :
1313#   - idx = eq!<eqname>
1314# Remplit :
1315#   - tab(eq!<eqname>!location) {<location> <blablah> }
1316#
1317# Historique :
1318#   2008/05/06 : pda      : conception
1319#
1320
1321proc juniper-parse-snmp-location {conf tab idx} {
1322    upvar $tab t
1323
1324    set error 0
1325    set ipmac 0
1326    set portmac 0
1327    set line [lindex $conf 1]
1328    if {[parse-location $line location ipmac portmac blablah msg]} then {
1329	if {! [string equal $location ""]} then {
1330	    set t($idx!location) [list $location $blablah]
1331	}
1332    } else {
1333	juniper-warning "$idx: $msg ($line)"
1334	set error 1
1335    }
1336
1337    set t($idx!ipmac) $ipmac
1338    set t($idx!portmac) $portmac
1339
1340    return $error
1341}
1342
1343#
1344# Entr�e :
1345#   - idx = eq!<eqname>
1346# Remplit :
1347#   - rien
1348#
1349# Historique :
1350#   2010/09/01 : pda/jean : conception
1351#
1352
1353proc juniper-parse-ethernet-swopt {conf tab idx} {
1354    upvar $tab t
1355
1356    array set kwtab {
1357	voip		{1	juniper-parse-voip}
1358	analyzer	{2	NOP}
1359	apply-groups	{2	NOP}
1360	apply-groups-except	{2      NOP}
1361	traceoptions	{1	NOP}
1362	*		{1	NOP}
1363    }
1364
1365    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1366}
1367
1368#
1369# Entr�e :
1370#   - idx = eq!<eqname>
1371# Remplit :
1372#   - rien
1373#
1374# Historique :
1375#   2010/09/01 : pda/jean : conception
1376#
1377
1378proc juniper-parse-voip {conf tab idx} {
1379    upvar $tab t
1380
1381    array set kwtab {
1382	interface	{2	juniper-parse-voip-iface}
1383	apply-groups	{2	NOP}
1384	apply-groups-except	{2      NOP}
1385	traceoptions	{1	NOP}
1386	*		{1	NOP}
1387    }
1388
1389    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1390}
1391
1392#
1393# Entr�e :
1394#   - idx = eq!<eqname>
1395# Remplit :
1396#   - tab(eq!<eqname>!voip!if!list) {ge-0/0/0 ...}
1397#   - tab(eq!<eqname>!voip!if!all) <existe ou non>
1398#   - tab(eq!<eqname>!voip!if!access-ports) <existe ou non>
1399#
1400# Historique :
1401#   2010/09/01 : pda/jean : conception
1402#
1403
1404proc juniper-parse-voip-iface {conf tab idx} {
1405    upvar $tab t
1406
1407    array set kwtab {
1408	vlan		{2	juniper-parse-voip-iface-vlan}
1409	apply-groups	{2	NOP}
1410	apply-groups-except	{2      NOP}
1411	traceoptions	{1	NOP}
1412	*		{2	NOP}
1413    }
1414
1415    #
1416    # l'interface peut �tre
1417    #	- all
1418    #	- access-ports : tous les ports access d�clar�s sur le switch
1419    #   - ge-n/n/n.0 : supprimer la "unit"
1420    #
1421
1422    set iface [lindex $conf 1]
1423
1424    switch $iface {
1425	all		{ set t($idx!voip!if!all) "yes" }
1426	access-ports	{ set t($idx!voip!if!access-ports) "yes" }
1427	default		{
1428	    if {[regexp {(.*)\.(\d)$} $iface bidon iface unit]} then {
1429		if {$unit != 0} then {
1430		    juniper-warning "$idx: invalid unit '$iface.$unit'"
1431		}
1432	    }
1433	    lappend t($idx!voip!if!list) $iface
1434	}
1435    }
1436
1437    set idx "$idx!voip!iface!$iface"
1438
1439    return [juniper-parse-list kwtab [lindex $conf 2] t $idx]
1440}
1441
1442#
1443# Entr�e :
1444#   - idx = eq!<eqname>!voip!iface!<iface>
1445# Remplit :
1446#   - tab(eq!<eqname>!voip!iface!<iface>!vlan) <id|nom|"untagged">
1447#
1448# Historique :
1449#   2010/09/01 : pda/jean : conception
1450#
1451
1452proc juniper-parse-voip-iface-vlan {conf tab idx} {
1453    upvar $tab t
1454
1455    set vlan [lindex $conf 1]
1456    set t($idx!vlan) $vlan
1457    return 0
1458}
1459
1460#
1461# Entr�e :
1462#   - idx = eq!<eqname>
1463# Remplit :
1464#   - rien
1465#
1466# Historique :
1467#   2009/12/21 : pda/jean : conception
1468#
1469
1470proc juniper-parse-vlans {conf tab idx} {
1471    upvar $tab t
1472
1473    array set kwtab {
1474	apply-groups	{2	NOP}
1475	apply-groups-except	{2      NOP}
1476	traceoptions	{1	NOP}
1477	*		{1	juniper-parse-vlans-entry}
1478    }
1479
1480    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1481}
1482
1483#
1484# Entr�e :
1485#   - idx = eq!<eqname>
1486# Remplit :
1487#   - tab(eq!<eqname>!vlans!names) {<nom> <nom> ...}
1488#
1489# Historique :
1490#   2010/01/04 : pda/jean : conception
1491#
1492
1493proc juniper-parse-vlans-entry {conf tab idx} {
1494    upvar $tab t
1495
1496    array set kwtab {
1497	description	{2	juniper-parse-vlans-entry-desc}
1498	vlan-id		{2	juniper-parse-vlans-entry-vlan-id}
1499	l3-interface	{2	juniper-parse-vlans-entry-l3-interface}
1500	interface	{1	juniper-parse-vlans-entry-interface}
1501    }
1502
1503    set nom [lindex $conf 0]
1504    set t(current!vlan-name) $nom
1505
1506    lappend t($idx!vlans!names) $nom
1507
1508    set r [juniper-parse-list kwtab [lindex $conf 1] t "$idx!vlans!name!$nom"]
1509    unset t(current!vlan-name)
1510
1511    return $r
1512}
1513
1514#
1515# Entr�e :
1516#   - idx = eq!<eqname>
1517# Remplit :
1518#   - tab(eq!<eqname>!vlans!names) {<nom> <nom> ...}
1519#
1520# Historique :
1521#   2010/03/24 : pda      : conception
1522#
1523
1524proc juniper-parse-vlans-entry-desc {conf tab idx} {
1525    upvar $tab t
1526
1527    # NOP pour l'instant
1528
1529    return 0
1530}
1531
1532#
1533# Entr�e :
1534#   - idx = eq!<eqname>!vlans!name!<nom>
1535# Remplit :
1536#   - tab(eq!<eqname>!vlans!name!<nom>!id) <vlanid>
1537#
1538# Historique :
1539#   2010/01/04 : pda/jean : conception
1540#
1541
1542proc juniper-parse-vlans-entry-vlan-id {conf tab idx} {
1543    upvar $tab t
1544
1545    set vlanid [lindex $conf 1]
1546    set t($idx!id) $vlanid
1547    return 0
1548}
1549
1550#
1551# Entr�e :
1552#   - idx = eq!<eqname>!vlans!name!<nom>
1553# Remplit :
1554#   - tab(eq!<eqname>!if!....!link!allowedvlans) {... {vlanid vlanid} ...}
1555#
1556# Historique :
1557#   2016/03/04 : boggia/jean : conception
1558#
1559
1560proc juniper-parse-vlans-entry-interface {conf tab idx} {
1561    upvar $tab t
1562
1563    #
1564    # get equipment name, current vlanid and interface bloc
1565    #
1566
1567    set eq [lindex [split $idx !] 1]
1568    set vlanid $t($idx!id)
1569    set ifaces [lindex $conf 1]
1570
1571    #
1572    # interface bloc is a list { ge-0/0/1.0 {} xe-0/2/1.0 {} ... }
1573    #
1574
1575    foreach {iface dummy} $ifaces {
1576        #
1577        # remove unit number
1578        #
1579        regexp {(.+)\.0$} $iface dummy iface
1580        set ifidx "eq!$eq!if!$iface!link!allowedvlans"
1581        lappend t($ifidx) [list $vlanid $vlanid]
1582    }
1583
1584    return 0
1585}
1586
1587
1588#
1589# Entr�e :
1590#   - idx = eq!<eqname>!vlans!name!<nom>
1591# Remplit :
1592#   - tab(eq!<eqname>!vlans!name!<nom>!l3) {<iface> <unit>}
1593#
1594# Historique :
1595#   2010/01/04 : pda/jean : conception
1596#
1597
1598proc juniper-parse-vlans-entry-l3-interface {conf tab idx} {
1599    upvar $tab t
1600
1601    set ifaceunit [lindex $conf 1]
1602    if {! [regexp {^(vlan|irb)\.([0-9]+)} $ifaceunit bidon iface unit]} then {
1603	juniper-warning "$idx: invalid l3-interface '$ifaceunit'"
1604    } else {
1605	set t($idx!l3) [list $iface $unit]
1606    }
1607    return 0
1608}
1609
1610#
1611# Entr�e :
1612#   - idx = eq!<eqname>
1613# Remplit :
1614#   - rien
1615#
1616# Historique :
1617#   2012/07/03 : pda/jean : conception
1618#
1619
1620proc juniper-parse-bridge-domains {conf tab idx} {
1621    upvar $tab t
1622
1623    array set kwtab {
1624	*		{1	juniper-parse-bridge-domains-entry}
1625    }
1626
1627    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1628}
1629
1630
1631#
1632# Entr�e :
1633#   - idx = eq!<eqname>
1634# Remplit :
1635#   - t(eq!<eq>!brdomlist) { <bdname> ...}
1636#
1637# Historique :
1638#   2012/07/03 : pda/jean : conception
1639#
1640
1641proc juniper-parse-bridge-domains-entry {conf tab idx} {
1642    upvar $tab t
1643
1644    array set kwtab {
1645	description		{2	NOP}
1646	domain-type		{2	NOP}
1647	bridge-options		{1	NOP}
1648	vlan-id			{2	juniper-parse-bridged-vlanid}
1649	vlan-id-list		{2	juniper-parse-bridged-vlanidlist}
1650	interface		{2	juniper-parse-bridged-if}
1651	routing-interface	{2	juniper-parse-bridged-routif}
1652	*			{2	ERROR}
1653    }
1654
1655    set bdname [lindex $conf 0]
1656    set bdparm [lindex $conf 1]
1657    set t(current!brdom) $bdname
1658    set t($idx!brdom!$bdname!iflist) {}
1659    set error [juniper-parse-list kwtab $bdparm t "$idx!brdom!$bdname"]
1660    if {! $error} then {
1661	lappend t($idx!brdomlist) $bdname
1662    }
1663    unset t(current!brdom)
1664
1665    return $error
1666}
1667
1668#
1669# Entr�e :
1670#   - idx = eq!<eqname>!brdom!<bdname>
1671# Remplit :
1672#   - t(eq!<eqname>!brdom!<bdname>!vlans) {{<vlanid> <vlanid>}}
1673#
1674# Historique :
1675#   2012/07/10 : pda/jean : conception
1676#
1677
1678proc juniper-parse-bridged-vlanid {conf tab idx} {
1679    upvar $tab t
1680
1681    set vlanid [lindex $conf 1]
1682    set t($idx!vlans) [list [list $vlanid $vlanid]]
1683    return 0
1684}
1685
1686#
1687# Entr�e :
1688#   - idx = eq!<eqname>!brdom!<bdname>
1689# Remplit :
1690#   - t(eq!<eqname>!brdom!<bdname>!vlans) {{<vlanid> <vlanid>} ... }
1691#
1692# Historique :
1693#   2012/07/10 : pda/jean : conception
1694#
1695
1696proc juniper-parse-bridged-vlanidlist {conf tab idx} {
1697    upvar $tab t
1698
1699    set t($idx!vlans) {}
1700    set vlans [lindex $conf 1]
1701    foreach v $vlans {
1702	if {[regexp {^(\d+)-(\d+)$} $v bidon min max]} then {
1703	    set l [list $min $max]
1704	} else {
1705	    set l [list $v $v]
1706	}
1707	lappend t($idx!vlans) $l
1708    }
1709    return 0
1710}
1711
1712#
1713# Entr�e :
1714#   - idx = eq!<eqname>!brdom!<bdname>
1715# Remplit :
1716#   - t(eq!<eqname>!brdom!<bdname>!vlans) {{<vlanid> <vlanid>} ... }
1717#
1718# Historique :
1719#   2012/07/10 : pda/jean : conception
1720#
1721
1722proc juniper-parse-bridged-if {conf tab idx} {
1723    upvar $tab t
1724
1725    set eq $t(eq)
1726    set brdom $t(current!brdom)
1727
1728    set ifname_unit [lindex $conf 1]
1729    if {[regexp {^(.*)\.(\d+)$} $ifname_unit bidon iface unit]} then {
1730	set error 0
1731	if {[info exists t(eq!$eq!if!$iface!vlans)]
1732	    && [lsearch -exact $t(eq!$eq!if!$iface!vlans) $unit] != -1} then {
1733	    #
1734	    # Mark this interface as participating to this bridge-domain
1735	    #
1736	    lappend t($idx!iflist) [list $iface $unit]
1737	    lappend t(eq!$eq!if!$iface!brdom) $brdom
1738
1739	} else {
1740	    juniper-warning "$eq: interface '$ifname_unit' not found in bridge domain"
1741	    set error 1
1742	}
1743    } else {
1744	juniper-warning "$eq: invalid interface '$ifname_unit' in bridge domain"
1745	set error 1
1746    }
1747
1748    return $error
1749}
1750
1751#
1752# Entr�e :
1753#   - idx = eq!<eqname>!brdom!<bdname>
1754# Remplit :
1755#	???????????????????????????????????????
1756#   - t(eq!<eqname>!brdom!<bdname>!vlans) {{<vlanid> <vlanid>} ... }
1757#
1758# Historique :
1759#   2012/07/10 : pda/jean : conception
1760#
1761
1762proc juniper-parse-bridged-routif {conf tab idx} {
1763    upvar $tab t
1764
1765    return 0
1766}
1767
1768#
1769# Entr�e :
1770#   - idx = eq!<eqname>
1771# Remplit :
1772#   - rien
1773#
1774# Historique :
1775#   2015/09/28 : jean : conception
1776#
1777
1778proc juniper-parse-protocols {conf tab idx} {
1779    upvar $tab t
1780
1781    array set kwtab {
1782	mvrp		{1	juniper-parse-protocols-mvrp}
1783	*		{1	NOP}
1784    }
1785
1786    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1787}
1788
1789#
1790# Entr�e :
1791#   - idx = eq!<eqname>
1792# Remplit :
1793#   - rien
1794#
1795# Historique :
1796#   2015/09/28 : jean : conception
1797#
1798
1799proc juniper-parse-protocols-mvrp {conf tab idx} {
1800    upvar $tab t
1801
1802    array set kwtab {
1803        interface                    {2      juniper-parse-mvrp-iface}
1804        apply-groups                 {2      NOP}
1805        apply-groups-except          {2      NOP}
1806        traceoptions                 {1      NOP}
1807        *                            {1      NOP}
1808    }
1809
1810    return [juniper-parse-list kwtab [lindex $conf 1] t $idx]
1811}
1812
1813
1814#
1815# Entr�e :
1816#   - idx = eq!<eqname>
1817# Remplit :
1818#   - tab(eq!<eqname>!if!<ifname>!link!allowvlans) ... {1 4094}
1819#
1820# Historique :
1821#   2015/09/28 : jean : adapted from parse-voip-iface
1822#
1823
1824proc juniper-parse-mvrp-iface {conf tab idx} {
1825    upvar $tab t
1826
1827    #
1828    # interface :
1829    #   - ge-n/n/n.0 : remove unit number
1830    #   - all : unsupported yet
1831    #
1832
1833    set iface [lindex $conf 1]
1834
1835    set error 0
1836    switch $iface {
1837	all		{
1838	    juniper-warning "$eq: mvrp interface all not supported"
1839            set error 1
1840	}
1841	default		{
1842	    if {[regexp {(.*)\.(\d)$} $iface bidon iface unit]} then {
1843		if {$unit != 0} then {
1844		    juniper-warning "$idx: invalid unit '$iface.$unit'"
1845		}
1846	    }
1847    	    set idx "$idx!if!$iface"
1848	    lappend t($idx!link!allowedvlans) [list 1 4094]
1849	}
1850    }
1851
1852    return $error
1853}
1854
1855###############################################################################
1856# Traitement apr�s analyse
1857###############################################################################
1858
1859#
1860# Traite le tableau r�sultant de l'analyse pour permettre d'acc�der
1861# plus facilement aux r�seaux (de niveau 3) et aux liens (de niveau 2)
1862# g�r�s par cet �quipement
1863#
1864# Entr�e :
1865#   - model : mod�le de l'�quipement
1866#   - fdout : descripteur de fichier pour la g�n�ration
1867#   - eq : nom de l'�quipement
1868#   - tab : tableau rempli au cours de l'analyse
1869# Sortie :
1870#   - valeur de retour : 0 si pas d'erreur, 1 si erreur
1871#   - tab : tableau modifi�
1872#
1873# Historique
1874#   2004/03/26 : pda/jean : conception
1875#   2004/06/08 : pda/jean : ajout du mod�le
1876#   2004/06/08 : pda/jean : changement de format du fichier de sortie
1877#   2006/06/01 : pda/jean : ajout snmp
1878#   2006/08/21 : pda/pegon : liens X+X+X+...+X deviennent X
1879#   2007/01/06 : pda       : ajout desc interface
1880#   2007/07/13 : pda       : ajout sortie tableau si debug
1881#   2010/03/25 : pda       : ajout "members all"
1882#   2010/09/01 : pda/jean  : ajout voip
1883#
1884
1885proc juniper-post-process {model fdout eq tab} {
1886    global debug
1887    upvar $tab t
1888
1889    if {$debug & 0x02} then {
1890	debug-array t
1891    }
1892
1893    if {[info exists t(eq!$eq!snmp)]} then {
1894	# XXX : on ne prend que la premi�re communaut� trouv�e
1895	set c [lindex $t(eq!$eq!snmp) 0]
1896    } else {
1897	set c "-"
1898    }
1899    if {[info exists t(eq!$eq!location)]} then {
1900	# XXX : on ne prend que la partie reconnue <...>
1901	set l [lindex $t(eq!$eq!location) 0]
1902    } else {
1903	set l "-"
1904    }
1905    if {[info exists t(eq!$eq!ipmac)]} then {
1906	set ipmac $t(eq!$eq!ipmac)
1907    } else {
1908	set ipmac 0
1909    }
1910    if {[info exists t(eq!$eq!portmac)]} then {
1911	set portmac $t(eq!$eq!portmac)
1912    } else {
1913	set portmac 0
1914    }
1915    puts $fdout "eq $eq type juniper model $model snmp $c location $l ipmac $ipmac portmac $portmac manual 0"
1916
1917    #
1918    # Parcourir la liste des interfaces, dont on compl�tera les
1919    # caract�ristiques selon les d�finitions des intervalles d�finis.
1920    # (JunOS switch)
1921    #
1922
1923    foreach if $t(eq!$eq!if) {
1924	set ranges [juniper-find-ranges t $eq $if]
1925	foreach r $ranges {
1926	    juniper-completer-iface t $eq $if $r
1927	}
1928
1929	#
1930	# Les interfaces non typ�es sont "ether" par d�faut
1931	#
1932
1933	set idx "eq!$eq!if!$if"
1934	if {! [info exists t($idx!link!type)]} then {
1935	    set t($idx!link!type) "ether"
1936	}
1937
1938	#
1939	# V�rifier que chaque interface a une description
1940	#
1941
1942	if {! [info exists t($idx!link!name)]} then {
1943	    juniper-warning "$eq/$if: link name in 'description' not found"
1944	    set error 1
1945	}
1946    }
1947
1948    #
1949    # Convertir les noms de vlans en id num�riques, phase 0
1950    # D�terminer les intervalles dans la liste des vlan-id trouv�s
1951    # sur cet �quipement
1952    #
1953
1954    if {[info exists t(eq!$eq!vlans!names)]} then {
1955	# d�terminer les vlan-id
1956	set lid {}
1957	foreach id [array names t -glob "*!vlans!name!*!id"] {
1958	    lappend lid $t($id)
1959	}
1960	set lid [lsort -integer $lid]
1961
1962	# d�terminer les intervalles
1963	set ranges {}
1964	set min [lindex $lid 0]
1965	set max [lindex $lid 0]
1966	foreach id [lreplace $lid 0 0] {
1967	    if {$max != $id - 1} then {
1968		lappend ranges [list $min $max]
1969		set min $id
1970	    }
1971	    set max $id
1972	}
1973	lappend ranges [list $min $max]
1974	set t(eq!$eq!vlans!ranges) $ranges
1975    }
1976
1977    #
1978    # Convertir les noms de vlans en id num�riques, phase 1
1979    # Remplacer "all" (members all) par la liste des vlans
1980    # connus dans la section "vlans"
1981    # (JunOS switch)
1982    #
1983
1984    if {[info exists t(eq!$eq!vlans!names)] && [info exists t(eq!$eq!vlans!ranges)]} then {
1985	# Parcourir toutes les "!allowedvlans" positionn�s
1986	# � "all all"
1987	foreach i [array names t -glob "*!link!allowedvlans"] {
1988	    set l {}
1989	    foreach c $t($i) {
1990		set v1 [lindex $c 0]
1991		set v2 [lindex $c 1]
1992		if {[string equal $v1 "all"] && [string equal $v2 "all"]} then {
1993		    set l [concat $l $t(eq!$eq!vlans!ranges)]
1994		} else {
1995		    lappend l [list $v1 $v2]
1996		}
1997	    }
1998	    set t($i) $l
1999	}
2000    }
2001
2002    #
2003    # Convertir les noms de vlans en id num�riques, phase 2
2004    # Mettre les interfaces vlan.<unit> dans le bon vlan-id
2005    # (JunOS switch)
2006    #
2007
2008    if {[info exists t(eq!$eq!vlans!names)]} then {
2009	foreach name $t(eq!$eq!vlans!names) {
2010	    #
2011	    # Conversion des noms de vlans : parcourir toutes les
2012	    # "!allowedvlans" pour convertir les noms
2013	    #
2014	    foreach i [array names t -glob "*!link!allowedvlans"] {
2015		set l {}
2016		foreach c $t($i) {
2017		    set v1 [lindex $c 0]
2018		    if {[info exists t(eq!$eq!vlans!name!$v1!id)]} then {
2019			set v1 $t(eq!$eq!vlans!name!$v1!id)
2020		    }
2021		    set v2 [lindex $c 1]
2022		    if {[info exists t(eq!$eq!vlans!name!$v2!id)]} then {
2023			set v2 $t(eq!$eq!vlans!name!$v2!id)
2024		    }
2025		    lappend l [list $v1 $v2]
2026		}
2027		set t($i) $l
2028	    }
2029
2030	    #
2031	    # Inscription des interfaces vlan.<unit> et irb.<unit> dans le bon
2032	    # vlan-id
2033	    #
2034	    foreach iftype {vlan irb} {
2035		array unset nt
2036		if {[info exists t(eq!$eq!vlans!name!$name!l3)]} then {
2037		    set ifaceunit $t(eq!$eq!vlans!name!$name!l3)
2038		    set iface [lindex $ifaceunit 0]
2039		    set unit  [lindex $ifaceunit 1]
2040		    if [string eq $iface $iftype] {
2041			set vlanid $t(eq!$eq!vlans!name!$name!id)
2042			lappend nt(eq!$eq!if!$iftype!vlans) $vlanid
2043			foreach i [array names t -glob "eq!$eq!if!$iface!vlan!$unit!*"] {
2044			    regexp "!$iface!vlan!$unit!(.*)" $i bidon reste
2045			    set nt(eq!$eq!if!$iface!vlan!$vlanid!$reste) $t($i)
2046			    unset t($i)
2047			}
2048			foreach i [array names nt] {
2049			    if {![info exists t($i)]} then {
2050			    	set t($i) {}
2051			    }
2052			    foreach e $nt($i) {
2053			    	lappend t($i) $e
2054			    }
2055			}
2056		    }
2057		}
2058	    }
2059	}
2060    }
2061
2062    #
2063    # Convertir les noms de vlans en id num�riques, phase 3
2064    # Convertir les native-vlan
2065    # (JunOS switch)
2066    #
2067
2068    if {[info exists t(eq!$eq!vlans!names)]} then {
2069	foreach name $t(eq!$eq!vlans!names) {
2070	    #
2071	    # Conversion des noms de vlans : parcourir toutes les
2072	    # "!allowedvlans" pour convertir les noms
2073	    #
2074	    set vlanid $t(eq!$eq!vlans!name!$name!id)
2075	    foreach i [array names t -glob "*!native-vlan"] {
2076		if {[string equal $name $t($i)]} then {
2077		    set t($i) $vlanid
2078		}
2079	    }
2080	}
2081    }
2082
2083    #
2084    # Convertir les noms de vlans en id num�riques, phase 4
2085    # Convertir les vlans sp�cifi�s dans les blocs "voip"
2086    # (JunOS switch)
2087    #
2088
2089    foreach iface [concat $t(eq!$eq!voip!if!list) {access-ports all}]] {
2090	if {[info exists t(eq!$eq!voip!iface!$iface!vlan)]} then {
2091	    set vlan $t(eq!$eq!voip!iface!$iface!vlan)
2092	    if {[info exists t(eq!$eq!vlans!name!$vlan!id)]} then {
2093		set vlanid $t(eq!$eq!vlans!name!$vlan!id)
2094		set t(eq!$eq!voip!iface!$iface!vlan) $vlanid
2095	    }
2096	}
2097    }
2098
2099    #
2100    # Traiter les sp�cifications "voip" sur les interfaces, phase 1
2101    # G�n�raliser les directives "access-ports" et "all" aux
2102    # interfaces concern�es.
2103    #
2104
2105    # pr�-traitement des access-ports
2106    if {[info exists t(eq!$eq!voip!if!access-ports)]} then {
2107	set vlanid $t(eq!$eq!voip!iface!access-ports!vlan)
2108	foreach iface $t(eq!$eq!if) {
2109	    if {! [string equal $iface "vlan"]} then {
2110		set linktype $t(eq!$eq!if!$iface!link!type)
2111		if {[string equal $linktype "ether"]} then {
2112		    if {! [info exists t(eq!$eq!voip!iface!$iface!vlan)]} then {
2113			set t(eq!$eq!voip!iface!$iface!vlan) $vlanid
2114			lappend t(eq!$eq!voip!if!list) $iface
2115		    }
2116
2117		}
2118	    }
2119	}
2120    }
2121
2122    # pr�-traitement des all
2123    if {[info exists t(eq!$eq!voip!if!all)]} then {
2124	set vlanid $t(eq!$eq!voip!iface!all!vlan)
2125	foreach iface $t(eq!$eq!if) {
2126	    if {! [string equal $iface "vlan"]} then {
2127		set linktype $t(eq!$eq!if!$iface!link!type)
2128		if {! [info exists t(eq!$eq!voip!iface!$iface!vlan)]} then {
2129		    set t(eq!$eq!voip!iface!$iface!vlan) $vlanid
2130		    lappend t(eq!$eq!voip!if!list) $iface
2131		}
2132	    }
2133	}
2134    }
2135
2136    # Propagate native-vlan information into allowed vlans
2137    foreach iface $t(eq!$eq!if) {
2138	if {[info exists t(eq!$eq!if!$iface!native-vlan)] &&
2139		[info exists t(eq!$eq!if!$iface!link!allowedvlans)]} then {
2140	    set nvlan $t(eq!$eq!if!$iface!native-vlan)
2141	    set allow {}
2142	    foreach cv $t(eq!$eq!if!$iface!link!allowedvlans) {
2143		lassign $cv min max
2144		if {$nvlan == $min} then {
2145		    incr min
2146		    if {$min < $max} then {
2147			lappend allow [list $min $max]
2148		    }
2149		} elseif {$nvlan == $max} then {
2150		    incr max -1
2151		    if {$min < $max} then {
2152			lappend allow [list $min $max]
2153		    }
2154		} elseif {$nvlan > $min && $nvlan < $max} then {
2155		    set nmax [expr $nvlan-1]
2156		    if {$min < $nmax} then {
2157			lappend allow [list $min $nmax]
2158		    }
2159		    set nmin [expr $nvlan+1]
2160		    if {$nmin < $max} then {
2161			lappend allow [list $nmin $max]
2162		    }
2163		} else {
2164		    lappend allow [list $min $max]
2165		}
2166	    }
2167	    set t(eq!$eq!if!$iface!link!allowedvlans) $allow
2168	}
2169    }
2170
2171    # Traiter les sp�cifications "voip" sur les interfaces, phase 2
2172    #
2173    # Ce qui est � faire d�pend du statut actuel de l'interface
2174    #	type	directive	action
2175    #	actuel	voip->vlan
2176    #	-------	------------	----------------------------------
2177    #	ether	<id>		passer en trunk pour <id> + native pour
2178    #				le vlan d�clar� en ether
2179    #	ether	untagged	aucun changement
2180    #	trunk	<id>		aucun changement de type + v�rifier que
2181    #				<id> figure dans les "allowedvlans"
2182    #	trunk	untagged	erreur
2183    #
2184
2185    foreach iface $t(eq!$eq!voip!if!list) {
2186	set disabled [info exists t(eq!$eq!if!$iface!disable)]
2187	if {! $disabled} then {
2188	    set id $t(eq!$eq!voip!iface!$iface!vlan)
2189	    set new "id"
2190	    if {[string equal $id "untagged"]} then {
2191		set new "untagged"
2192	    }
2193
2194	    set linktype $t(eq!$eq!if!$iface!link!type)
2195
2196	    switch "$linktype-$new" {
2197		ether-id {
2198		    set t(eq!$eq!if!$iface!link!type) trunk
2199
2200		    if {[info exist t(eq!$eq!if!$iface!link!allowedvlans)]} then {
2201			set a [lindex $t(eq!$eq!if!$iface!link!allowedvlans) 0]
2202			set oldvlan [lindex $a 0]
2203			set t(eq!$eq!if!$iface!native-vlan) $oldvlan
2204		    }
2205		    lappend t(eq!$eq!if!$iface!link!allowedvlans) [list $id $id]
2206		}
2207		ether-untagged {
2208		    # aucun changement
2209		}
2210		trunk-id {
2211		    set found 0
2212		    foreach c $t(eq!$eq!if!$iface!link!allowedvlans) {
2213			set v1 [lindex $c 0]
2214			set v2 [lindex $c 1]
2215			if {$id >= $v1 && $id <= $v2} then {
2216			    set found 1
2217			    break
2218			}
2219		    }
2220		    if {! $found} then {
2221			lappend t(eq!$eq!if!$iface!link!allowedvlans) [list $id $id]
2222		    }
2223		}
2224		trunk-untagged {
2225		    juniper-warning "Inconsistent voip specification on '$eq/$iface'"
2226		}
2227		default {
2228		    juniper-warning "Internal error for voip on '$eq/$iface'"
2229		}
2230	    }
2231	}
2232    }
2233
2234    #
2235    # Chercher tous les liens. Pour cela, parcourir la liste
2236    # des interfaces
2237    #
2238    catch {unset agtab}
2239
2240    # premi�re boucle pour constituer les noms des liens agr�g�s
2241    foreach iface $t(eq!$eq!if) {
2242	set linkname $t(eq!$eq!if!$iface!link!name)
2243	set linktype $t(eq!$eq!if!$iface!link!type)
2244	if {[string equal $linktype "aggregate"]} then {
2245	    set parentif $t(eq!$eq!if!$iface!link!ifname)
2246	    lappend agtab($parentif) $linkname
2247	}
2248    }
2249
2250    #
2251    # On JunOS router, interface may candidate to some declared
2252    # bridge domains or may be explicitely named by a bridge domain
2253    # declaration.
2254    # Explore all bridge domains to generate bridge (or bridge pattern)
2255    # nodes, and mark selected interfaces.
2256    #
2257
2258    foreach brdom $t(eq!$eq!brdomlist) {
2259	#
2260	# If this is a bridge domain with only one specified
2261	# vlan, instantiate a bridge node specific for this vlan
2262	# and not a bridge pattern (brpat) to instanciate.
2263	#
2264
2265	set brnode 0
2266	set vlans $t(eq!$eq!brdom!$brdom!vlans)
2267	if {[llength $vlans] <= 1} then {
2268	    lassign [lindex $vlans 0] min max
2269	    if {$min eq $max} then {
2270		set brnode [newnode]
2271		puts $fdout "node $brnode type bridge eq $eq"
2272		set t(eq!$eq!brdom!$brdom!brnode) $brnode
2273
2274		#
2275		# Mark (with the bridge node) all interfaces explicitely
2276		# named in this bridge domain
2277		#
2278
2279		foreach iface_unit $t(eq!$eq!brdom!$brdom!iflist) {
2280		    lassign $iface_unit iface unit
2281		    lappend t(eq!$eq!if!$iface!bridges) [list $brnode $unit $unit]
2282		}
2283	    }
2284	}
2285
2286	#
2287	# Gathers all interfaces which candidate to this bridge
2288	#
2289
2290	foreach cv $vlans {
2291	    # vlans allowed on the bridge
2292	    lassign $cv brmin brmax
2293
2294	    foreach iface $t(eq!$eq!brcandidate) {
2295		set allow {}
2296		foreach ca $t(eq!$eq!if!$iface!link!allowedvlans) {
2297		    lassign $ca amin amax
2298
2299		    #
2300		    # Check intersection of intervals by computing
2301		    # the resulting interval.
2302		    #
2303		    # nmin = max (amin, brmin)
2304		    # nmax = min (amax, brmax)
2305		    #
2306		    set nmin [expr $amin < $brmin ? $brmin : $amin]
2307		    set nmax [expr $amax > $brmax ? $brmax : $amax]
2308		    if {$nmin <= $nmax} then {
2309			lappend t(eq!$eq!if!$iface!bridges) [list $brnode $nmin $nmax]
2310		    }
2311		}
2312	    }
2313	}
2314    }
2315
2316    # XXX : pour l'instant, il n'y a qu'une seule instance de routage
2317    # dans *nos* Juniper...
2318    # En fait, il y en a deux : la "default" pour v4 et la "default" pour v6
2319
2320    set nodeR4 ""
2321    set nodeR6 ""
2322
2323    #
2324    # Boucle principale : retrouver les liens de niveau 2
2325    # (sans le d�tail des constituants d'un lien agr�g�)
2326    # Parcourir la liste des interfaces.
2327    #
2328
2329    # par d�faut, pas de brpat
2330    set nodebrpat 0
2331
2332    if {$debug & 0x02} then {
2333	debug-array t
2334    }
2335
2336    foreach iface $t(eq!$eq!if) {
2337	if {[info exists agtab($iface)]} then {
2338	    #
2339	    # Si tous les liens sont "X", constituer un lien "X"
2340	    # au lieu d'un lien "X+X+X+..+X"
2341	    #
2342	    set tousX 1
2343	    foreach l $agtab($iface) {
2344		if {! [string equal $l "X"]} then {
2345		    set tousX 0
2346		    break
2347		}
2348	    }
2349	    if {$tousX} then {
2350		set linkname "X"
2351	    } else {
2352		set linkname [join [lsort $agtab($iface)] "+"]
2353	    }
2354	} else {
2355	    set linkname $t(eq!$eq!if!$iface!link!name)
2356	}
2357	set statname $t(eq!$eq!if!$iface!link!stat)
2358	if {[string equal $statname ""]} then {
2359	    set statname "-"
2360	}
2361	set desc $t(eq!$eq!if!$iface!link!desc)
2362	if {[string equal $desc ""]} then {
2363	    set desc "-"
2364	}
2365	set linktype $t(eq!$eq!if!$iface!link!type)
2366
2367	if {[string equal $iface "vlan"] || [string equal $iface "irb"]} then {
2368	    #
2369	    # Traitement sp�cial pour les interface "vlan" et "irb" qu'on
2370	    # trouve sur les JunOS switch
2371	    # Cas r�duit d'une interface physique sur JunOS routeur
2372	    #
2373
2374	    if {[info exists t(eq!$eq!if!$iface!vlans)]} then {
2375		foreach v $t(eq!$eq!if!$iface!vlans) {
2376		    set nodeL2 [newnode]
2377		    set t(eq!$eq!if!$iface!vlan!$v!node) $nodeL2
2378		    if {![info exists t(eq!$eq!if!$iface!vlan!$v!stat)]} {
2379			juniper-warning "Warning: '$iface.$v' l3-interface not defined"
2380			continue
2381		    }
2382		    set statname $t(eq!$eq!if!$iface!vlan!$v!stat)
2383		    if {[string equal $statname ""]} then {
2384			set statname "-"
2385		    }
2386		    puts $fdout "node $nodeL2 type L2 eq $eq vlan $v stat $statname native 0 ifname -"
2387		    puts $fdout "link $nodeL2 $nodebrpat"
2388
2389		    #
2390		    # Parcourir la liste des r�seaux support�s par cette
2391		    # sous-interface.
2392		    #
2393		    foreach cidr $t(eq!$eq!if!$iface!vlan!$v!networks) {
2394			set ifname "$iface.$v"
2395			set idx "eq!$eq!if!$iface!vlan!$v!net!$cidr"
2396
2397			# r�cup�rer l'adresse du routeur dans ce r�seau
2398			# (i.e. l'adresse IP de l'interface)
2399			set gwadr $t($idx)
2400			set preflen $t($idx!preflen)
2401			set nodeL3 [newnode]
2402
2403			puts $fdout "node $nodeL3 type L3 eq $eq addr $gwadr/$preflen"
2404			puts $fdout "link $nodeL3 $nodeL2"
2405		    }
2406		}
2407	    }
2408
2409	} elseif {! [string equal $linktype "aggregate"]} then {
2410	    #
2411	    # Cas standard pour toutes les interfaces physiques
2412	    # (non constituant un lien aggr�g�)
2413	    #
2414
2415	    set nodeL1 [newnode]
2416	    puts $fdout "node $nodeL1 type L1 eq $eq name $iface link $linkname encap $linktype stat $statname desc $desc"
2417
2418	    if {[info exists t(eq!$eq!if!$iface!l2switch)]} then {
2419		#
2420		# Interface de JunOS switch : "family ethernet-switching"
2421		#
2422
2423		set nodeL2 [newnode]
2424
2425		switch -- $t(eq!$eq!if!$iface!link!type) {
2426		    ether {
2427			if {[info exists t(eq!$eq!if!$iface!link!allowedvlans)]} then {
2428			    set a [lindex $t(eq!$eq!if!$iface!link!allowedvlans) 0]
2429			    set v [lindex $a 0]
2430			    puts $fdout "node $nodeL2 type L2 eq $eq vlan $v stat - native 1 ifname -"
2431			} else {
2432			    set nodeL2 ""
2433			}
2434		    }
2435		    trunk {
2436			puts -nonewline $fdout "node $nodeL2 type L2pat eq $eq"
2437			foreach allowedvlans $t(eq!$eq!if!$iface!link!allowedvlans) {
2438			    set v1 [lindex $allowedvlans 0]
2439			    set v2 [lindex $allowedvlans 1]
2440			    puts -nonewline $fdout " allow $v1 $v2"
2441			}
2442			if {[info exists t(eq!$eq!if!$iface!native-vlan)]} then {
2443			    set nv $t(eq!$eq!if!$iface!native-vlan)
2444			    puts -nonewline $fdout " native $nv"
2445			}
2446			puts $fdout ""
2447		    }
2448		    default {
2449			juniper-warning "Unknown link type for '$eq/$iface'"
2450		    }
2451		}
2452
2453		if {! [string equal $nodeL2 ""]} then {
2454		    puts $fdout "link $nodeL1 $nodeL2"
2455		    if {$nodebrpat == 0} then {
2456			set nodebrpat [newnode]
2457			puts $fdout "node $nodebrpat type brpat eq $eq"
2458		    }
2459		    puts $fdout "link $nodeL2 $nodebrpat"
2460		}
2461
2462	    } else {
2463		#
2464		# Interface de JunOS routeur : "family inet[6]"
2465		#
2466
2467		switch $linktype {
2468		    ether {
2469			# VLAN = 0 pour un lien Ether
2470			set arg 0
2471		    }
2472		    trunk {
2473			set arg {}
2474			if {[info exists t(eq!$eq!if!$iface!vlans)]} then {
2475			    # Liste des vlans pour ce lien
2476			    set arg $t(eq!$eq!if!$iface!vlans)
2477			}
2478		    }
2479		    default {
2480			juniper-warning "Unknown link type for '$eq/$iface"
2481		    }
2482		}
2483
2484		foreach v $arg {
2485		    if {! [info exists t(eq!$eq!if!$iface!vlan!$v!disable)]} then {
2486			if {[info exists t(eq!$eq!if!$iface!vlan!$v!networks)]} then {
2487			    #
2488			    # Interconnexion des VLAN aux interfaces physiques
2489			    #
2490			    set nodeL2 [newnode]
2491			    set t(eq!$eq!if!$iface!vlan!$v!node) $nodeL2
2492			    set statname $t(eq!$eq!if!$iface!vlan!$v!stat)
2493			    if {[string equal $statname ""]} then {
2494				set statname "-"
2495			    }
2496			    if {$v == 0} then {
2497				set native 1
2498			    } else {
2499				set native 0
2500			    }
2501			    puts $fdout "node $nodeL2 type L2 eq $eq vlan $v stat $statname native $native ifname -"
2502			    puts $fdout "link $nodeL1 $nodeL2"
2503
2504			    #
2505			    # Parcourir la liste des r�seaux support�s par cette
2506			    # sous-interface.
2507			    #
2508			    foreach cidr $t(eq!$eq!if!$iface!vlan!$v!networks) {
2509				set ifname "$iface.$v"
2510				set idx "eq!$eq!if!$iface!vlan!$v!net!$cidr"
2511
2512				# r�cup�rer l'adresse du routeur dans ce r�seau
2513				# (i.e. l'adresse IP de l'interface)
2514				set gwadr $t($idx)
2515				set preflen $t($idx!preflen)
2516				set nodeL3 [newnode]
2517
2518				puts $fdout "node $nodeL3 type L3 eq $eq addr $gwadr/$preflen"
2519				puts $fdout "link $nodeL3 $nodeL2"
2520
2521				if {[string first ":" $gwadr] != -1} then {
2522				    if {[string equal $nodeR6 ""]} then {
2523					set nodeR6 [newnode]
2524					puts $fdout "node $nodeR6 type router eq $eq instance _v6"
2525				    }
2526				    set nodeR $nodeR6
2527				} else {
2528				    if {[string equal $nodeR4 ""]} then {
2529					set nodeR4 [newnode]
2530					puts $fdout "node $nodeR4 type router eq $eq instance _v4"
2531				    }
2532				    set nodeR $nodeR4
2533				}
2534
2535				puts $fdout "link $nodeL3 $nodeR"
2536
2537				set static {}
2538
2539				# parcourir les passerelles cit�es dans les routes statiques,
2540				# pour d�terminer celles qui sont dans *ce* r�seau
2541				if {[info exists t(eq!$eq!static!gw)]} then {
2542				    foreach gw $t(eq!$eq!static!gw) {
2543					set r [juniper-match-network $gw $cidr]
2544					if {$r == -1} then {
2545					    return 1
2546					} elseif {$r} then {
2547					    foreach n $t(eq!$eq!static!$gw) {
2548						append static "$n $gw "
2549					    }
2550					}
2551				    }
2552				}
2553
2554				# est-ce qu'il y a du VRRP sur cette interface pour ce r�seau ?
2555				if {[info exists t($idx!vrrp!virtual)]} then {
2556				    set vrrp "$t($idx!vrrp!virtual) $t($idx!vrrp!priority)"
2557				} else {
2558				    set vrrp "- -"
2559				}
2560
2561				puts $fdout "rnet $cidr $nodeR $nodeL3 $nodeL2 $nodeL1 $vrrp $static"
2562			    }
2563			}
2564		    }
2565		}
2566
2567		#
2568		# Output interfaces (on JunOS router) marked as
2569		# participating to a bridge domain
2570		#
2571
2572		if {[info exists t(eq!$eq!if!$iface!bridges)]} then {
2573		    #
2574		    # This interface has at least one unit which
2575		    # participates to a bridge-domain
2576		    #
2577		    foreach b $t(eq!$eq!if!$iface!bridges) {
2578			lassign $b brnode min max
2579
2580			if {$brnode == 0} then {
2581			    if {$nodebrpat == 0} then {
2582				set nodebrpat [newnode]
2583				puts $fdout "node $nodebrpat type brpat eq $eq"
2584			    }
2585			    set brnode $nodebrpat
2586			}
2587
2588			# Is there a sensor?
2589			set statname ""
2590			if {$min == $max} then {
2591			    # if this unit has a specific description
2592			    # it may have a declared sensor
2593			    if {[info exists t(eq!$eq!if!$iface!vlan!$min!stat)]} then {
2594				set statname $t(eq!$eq!if!$iface!vlan!$min!stat)
2595			    }
2596			}
2597			if {$statname eq ""} then {
2598			    set statname "-"
2599			}
2600
2601			# native vlan ?
2602			set native 0
2603			if {$t(eq!$eq!if!$iface!link!type) eq "ether"} then {
2604			    set native 1
2605			}
2606			if {[info exists t(eq!$eq!if!$iface!native-vlan)]} then {
2607			    set nv $t(eq!$eq!if!$iface!native-vlan)
2608			    if {$min == $max && $min == $nv} then {
2609				set native 1
2610			    }
2611			}
2612
2613			set nodeL2 [newnode]
2614			if {$min == $max} then {
2615			    set ntype "L2"
2616			    set allow "vlan $min"
2617			} else {
2618			    set ntype "L2pat"
2619			    set allow "allow $min $max"
2620			}
2621			puts $fdout "node $nodeL2 type $ntype eq $eq $allow stat $statname native $native ifname -"
2622			puts $fdout "link $nodeL1 $nodeL2"
2623			puts $fdout "link $nodeL2 $brnode"
2624		    }
2625		}
2626	    }
2627	}
2628    }
2629
2630    #
2631    # Parcourir la liste des interfaces marqu�es "disable"
2632    #
2633
2634    foreach iface $t(eq!$eq!if!disabled) {
2635	if {! [string equal $iface "vlan"]} then {
2636	    set nodeL1 [newnode]
2637	    puts $fdout "node $nodeL1 type L1 eq $eq name $iface link X encap disabled stat - desc -"
2638	}
2639    }
2640
2641    return 0
2642}
2643
2644proc juniper-find-ranges {tab eq if} {
2645    upvar $tab t
2646
2647    set lr {}
2648    if {[regexp {^[A-Za-z]+-.*} $if]} then {
2649	foreach r $t(eq!$eq!ranges) {
2650	    set lc $t(eq!$eq!range!$r!members)
2651	    foreach c $lc {
2652		set min [lindex $c 0]
2653		set max [lindex $c 1]
2654		if {[juniper-iface-cmp $if $min]>=0 && [juniper-iface-cmp $if $max]<=0} then {
2655		    lappend lr $r
2656		    break
2657		}
2658	    }
2659	}
2660    }
2661    return $lr
2662}
2663
2664proc juniper-iface-cmp {i1 i2} {
2665    if {! [regexp {^([A-Za-z]+)-(.*)} $i1 bidon n1 r1]} then {
2666	puts stderr "Invalid interface name '$i1' (range $i1 $i2)"
2667	return -1
2668    }
2669    if {! [regexp {^([A-Za-z]+)-(.*)} $i2 bidon n2 r2]} then {
2670	puts stderr "Invalid interface name '$i2'"
2671	return -1
2672    }
2673
2674    set l1 [split $r1 "/"]
2675    set l2 [split $r2 "/"]
2676
2677    set r [string compare $n1 $n2]
2678    if {$r == 0} then {
2679	foreach e1 $l1 e2 $l2 {
2680	    if {$e1 < $e2} then {
2681		set r -1
2682		break
2683	    } elseif {$e1 > $e2} then {
2684		set r 1
2685		break
2686	    }
2687	}
2688    }
2689
2690    return $r
2691}
2692
2693proc juniper-completer-iface {tab eq if range} {
2694    upvar $tab t
2695
2696    foreach e {link!name link!desc link!stat link!type link!ifname} {
2697	if {[info exists t(eq!$eq!if!$if!$e)] && ! [string equal $t(eq!$eq!if!$if!$e) ""]} then {
2698	    # rien � faire
2699	} else {
2700	    if {[info exists t(eq!$eq!range!$range!$e)]} then {
2701		set t(eq!$eq!if!$if!$e) $t(eq!$eq!range!$range!$e)
2702	    }
2703	}
2704    }
2705}
2706
2707###############################################################################
2708# Initialisation du module
2709###############################################################################
2710
2711juniper-init
2712