0001 /*
0002 *
0003 * NAME: range.slax
0004 * PURPOSE: To allow the user to issue select attributes on a range of
0005 * interfaces. Interfaces must be on the same "dpc" and "pic"
0006 * on EX-series switches. Interfaces must be on the same "dpc"
0007 * for MX-series switches.
0008 *
0009 * CREATED: 09/05/08
0010 * BY: Jay Wilson (Southwest Regional JUNOS Specialist)
0011 * LAST MOD: 10/27/08
0012 * BY: Jay Wilson
0013 * VERSION: 3.02
0014 *
0015 * MODIFICATION HISTORY:
0016 * V1.00 = Initial release
0017 * V1.01 = Changed the parm names for the macro to match the JUNOS
0018 * names (vname ==> vlan, vid ==> vlan-id, mode ==> port-mode)
0019 * V1.02 = Added a parm called "remove".
0020 * It has no options.
0021 * If it is specificed in the macro, that macro will be
0022 * removed from the configuration upon a successful commit.
0023 * V1.03 = Added a check to ensure the script is running on an EX device.
0024 * V1.04 = Removed warning messages when script is run.
0025 * Added a check for a ztrace option in the macro that
0026 * if specified calls WRITE-MSG to print out a
0027 * warning message showing what changes will happen
0028 * to each interface.
0029 * V2.00 = Major rewrite!!
0030 * Modularized the code via templates.
0031 * Added support for the "setv" option, which allows the
0032 * user to put the interface into the VLANS
0033 * hierarchy instead of putting the vlan name on
0034 * the interface in the INTERFACES hierarchy
0035 * V3.00 = Major rewrite!!
0036 * Added support for MX-series at the request of the EABU.
0037 * Several new templates were added to support the
0038 * specific requirements of the MX.
0039 * The device check was modified to allow the script
0040 * to work on both the EX-series and MX-Series.
0041 * The range macro is still limited to a single PIC
0042 * for EX member, but for the MX it can cross PICs on
0043 * the same DPC.
0044 * The same marcro syntax is used for both MX and EX
0045 * and the script translates the options for each
0046 * series.
0047 * V3.01 = MX-series changes
0048 * Removed unused macro options
0049 * V3.02 = EX & MX changes
0050 * Added "description" option, which allows the
0051 * user to put a description on all interfaces
0052 * specified.
0053 *
0054 *
0055 * HOW TO USE:
0056 * This script will be called for each "apply-macro" found in the
0057 * configuration that starts with "range". There is no limited to
0058 * the number of times it may be called in a configuration.
0059 *
0060 * Additionally, if the vlan specificed to be placed on the interfaces
0061 * does not exist in "vlans", the vlan will be created and the "vlan-id"
0062 * will be added if the "vlan-id" parm is passed to the script.
0063 *
0064 * Parms:
0065 * "action delete" (will delete what ever is specified)
0066 * (the interface if no vlan or mode is specified)
0067 * (if mode and/or vlan is specified only they are
0068 * delete)
0069 * "mode trunk" (sets the interface's port-mode to trunk)
0070 * ("access" is the default and implied)
0071 * "from xx" (the interface to start the range at)
0072 * "to xx" (the interface to stop the range at)
0073 * "vlan-id xx" (the tag number for the vlan)
0074 * (this is not needed for the interface.
0075 * it is only used if the vlan does not exist
0076 * in vlans)
0077 * "vlan xx" (the vlan name to add to the port)
0078 * "remove" (remove the range macro upon successful
0079 * commit or commit check)
0080 * "ztrace" (turns on debugging)
0081 * "setv" (puts the interface into the VLANS
0082 * hierarchy instead of putting the
0083 * vlan name on the interface)
0084 *
0085 * Example 1:
0086 * Add vlan "red" to interfaces ge-0/0/0 through ge-0/0/10
0087 * and if the vlan has not been created, create it and
0088 * set the vlan-id.
0089 *
0090 * apply-macro range {
0091 * from ge-0/0/0
0092 * to ge-0/0/10
0093 * vlan-id 10
0094 * vlan red
0095 * }
0096 *
0097 * Example 2:
0098 * Make ge-3/1/0 through ge-3/1/3 trunk ports and delete
0099 * the macro from the configuration.
0100 *
0101 * apply-macro range2 {
0102 * from ge-3/1/0
0103 * to ge-3/1/3
0104 * mode trunk
0105 * remove
0106 * }
0107 *
0108 * Example 3:
0109 * Delete ge-1/0/0 through ge-1/0/5
0110 *
0111 * apply-macro range3 {
0112 * from ge-1/0/0
0113 * to ge-1/0/5
0114 * action delete
0115 * }
0116 *
0117 * Example 4:
0118 * Add vlan "red" to interfaces ge-4/0/5 through ge-4/0/10
0119 * and if the vlan has not been created, create it and
0120 * set the vlan-id.
0121 * Additionally, make them trunk ports.
0122 *
0123 * apply-macro range4 {
0124 * from ge-4/0/5
0125 * to ge-4/0/10
0126 * vlan-id 10
0127 * mode trunk
0128 * vlan red
0129 * }
0130 *
0131 * Example 5:
0132 * Add interfaces ge-4/0/5 through ge-4/0/10 to vlan red
0133 * and if the vlan has not been created, create it and
0134 * set the vlan-id.
0135 * Additionally, make the interfaces trunk ports and
0136 * delete the macro upon a successful commit or
0137 * commit check.
0138 *
0139 *
0140 * apply-macro range4 {
0141 * from ge-4/0/5
0142 * to ge-4/0/10
0143 * vlan-id 10
0144 * mode trunk
0145 * vlan red
0146 * setv
0147 * remove
0148 * }
0149 *
0150 */
0151 version 1.0;
0152 ns junos = "http://xml.juniper.net/junos/*/junos";
0153 ns xnm = "http://xml.juniper.net/xnm/1.1/xnm";
0154 ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0";
0155 import "../import/junos.xsl";
0156 match configuration {
0157 /*
0158 *
0159 * get the device information before entering the macro processing loop
0160 *
0161 * Only SNMP returns a consistantly formated result for all Juniper
0162 * platforms.
0163 *
0164 */
0165 var $rpc-cmd = {
0166 <get-snmp-object> {
0167 <snmp-object-name>"1.3.6.1.2.1.1.2.0";
0168 }
0169 }
0170 var $sysobjid = jcs:invoke($rpc-cmd);
0171 var $sub-sysobjid = substring-after($sysobjid,"jnxProduct");
0172 var $model = substring-before($sub-sysobjid,"\n");
0173
0174 /*
0175 *
0176 * Make sure the macro and script are used on a supported device type
0177 * and if they are, select the correct templates to use
0178 *
0179 */
0180 if (contains($model,"EX") || contains($model,"ex")) {
0181 call ex-main;
0182 }
0183 else if (contains($model,"MX") || contains($model,"mx")) {
0184 call mx-main;
0185 }
0186 else {
0187 <xnm:error> {
0188 <message> "RANGE ERROR: Macro is only supported on EX-series and MX-Series";
0189 }
0190 }
0191 }
0192
0193 /******************************************************************/
0194 /* */
0195 /* EX Specific Templates */
0196 /* */
0197 /******************************************************************/
0198
0199 template ex-main {
0200
0201 /* Save the candidate node set point for vlans */
0202
0203 var $vnode = ./vlans;
0204
0205 /*
0206 * Process the apply-macros
0207 * Only look at macros that start with "range"
0208 *
0209 */
0210 for-each (apply-macro[starts-with(name,"range")]) {
0211 var $vlan = data[name = 'vlan']/value;
0212 var $vlan-id = data[name = 'vlan-id']/value;
0213 var $from = data[name = 'from']/value;
0214 var $to = data[name = 'to']/value;
0215 var $action = data[name = 'action']/value;
0216 var $port-mode = data[name = 'port-mode']/value;
0217 var $fromtype = substring-before($from,'-');
0218 var $totype = substring-before($to,'-');
0219 var $description = data[name = 'description']/value;
0220 /* check to see if macro should be delete on successful commit */
0221 var $bitbucket = { if (data[name = 'remove']) {
0222 expr name;
0223 }
0224 else {
0225 expr "";
0226 }
0227 }
0228 /* check to see if macro tracing was turned on */
0229 var $trace = { if (data[name = 'ztrace']) {
0230 expr "ztrace";
0231 }
0232 else {
0233 expr "";
0234 }
0235 }
0236 /* check to see if set location was turned on */
0237 var $set-loc = { if (data[name = 'setv']) {
0238 expr "setv";
0239 }
0240 else {
0241 expr "";
0242 }
0243 }
0244 if (not($fromtype =='') and not($totype =='') and $fromtype == $totype and ($fromtype == "ge" ||$fromtype == "xe") and ($totype == "ge" || $totype == "xe")) {
0245
0246 /* Split up the Interfaces into DPC, PIC, PORT */
0247
0248 var $fromtriple = substring-after($from,'-');
0249 var $fromoct1 = substring-before($fromtriple,'/');
0250 var $fromleft = substring-after($fromtriple,'/');
0251 var $fromoct2 = substring-before($fromleft,'/');
0252 var $fromoct3 = substring-after($fromleft,'/');
0253 var $totriple = substring-after($to,'-');
0254 var $tooct1 = substring-before($totriple,'/');
0255 var $toleft = substring-after($totriple,'/');
0256 var $tooct2 = substring-before($toleft,'/');
0257 var $tooct3 = substring-after($toleft,'/');
0258 /* If the vlan doesn't exist, create it and add the vlan-id */
0259 /* if it was supplied. */
0260 /* The vlan is created to avoid warning messages on the commit. */
0261 /* Put a vlan on an Interface without the vlan existing in */
0262 /* vlans, causes the warning. */
0263 if ($vlan and not($action == "delete")) {
0264 <change> {
0265 <vlans> {
0266 <vlan> {
0267 <name> $vlan;
0268 if ($vlan-id) {
0269 <vlan-id> $vlan-id;
0270 }
0271 }
0272 }
0273 }
0274 }
0275 /* Validate the information supplied in the macro */
0276 /* */
0277 if (not($fromoct1) || not($fromoct2) || not($fromoct3) || not($tooct1) || not($tooct2) || not($tooct3)) {
0278 <xnm:error> {
0279 <message> "RANGE ERROR: Invalid Interface Format";
0280 }
0281 }
0282 else if (not($fromoct1 == $tooct1)) {
0283 <xnm:error> {
0284 <message> "RANGE ERROR: From Member != To Member";
0285 }
0286 }
0287 else if (not($fromoct2 == $tooct2)) {
0288 <xnm:error> {
0289 <message> "RANGE ERROR: From and To PIC must match";
0290 }
0291 }
0292 else if ($fromoct1 == $tooct1 and $fromoct2 > $tooct2) {
0293 /* Should not be called until multi-member is supported */
0294 <xnm:error> {
0295 <message> "RANGE ERROR: From PIC >= To PIC on same Member";
0296 }
0297 }
0298 else if ($fromtype == "xe" and $fromoct2 != 1) { /* remove this if when all 10G switch is available */
0299 <xnm:error> {
0300 <message> "RANGE ERROR: xe- interfaces only supported on PIC 1";
0301 }
0302 }
0303 else if ($fromoct1 == $tooct1 and $fromoct2 == $tooct2 and $fromoct3 >= $tooct3) {
0304 <xnm:error> {
0305 <message> "RANGE ERROR: From Port >= To Port on same Member/PIC";
0306 }
0307 }
0308 else if ($fromoct1 > 9 || $tooct1 > 9) {
0309 <xnm:error> {
0310 <message> "RANGE ERROR: Member must be 0 to 9";
0311 }
0312 }
0313 else if ($fromoct2 > 1 || $tooct2 > 1) {
0314 <xnm:error> {
0315 <message> "RANGE ERROR: PIC must be 0 or 1";
0316 }
0317 }
0318 else if ($fromtype == "xe" and $fromoct2 != 1) {
0319 <xnm:error> {
0320 <message> "RANGE ERROR: PIC must be 1 for xe- Interfaces";
0321 }
0322 }
0323 else if ($fromoct2 == 1 and (($fromoct3 > 3 || $tooct3 > 3) and $fromtype == "ge")) {
0324 <xnm:error> {
0325 <message> "RANGE ERROR: GE PIC Interfaces Must be < 4";
0326 }
0327 }
0328 else if ($fromoct2 == 1 and (($fromoct3 > 1 || $tooct3 > 1) and $fromtype == "xe")) {
0329 <xnm:error> {
0330 <message> "RANGE ERROR: XE PIC Interfaces Must be < 2";
0331 }
0332 }
0333 else if (not($vlan) and not($port-mode) and not($action)) {
0334 <xnm:error> {
0335 <message> "RANGE ERROR: Macro MUST include a vlan and/or MODE";
0336 }
0337 }
0338 else if ($action and not($action == "delete")) {
0339 <xnm:error> {
0340 <message> "RANGE ERROR: Valid ACTION is delete. set is implied.";
0341 }
0342 }
0343 else if ($port-mode and not($port-mode == "trunk")) {
0344 <xnm:error> {
0345 <message> "RANGE ERROR: Valid MODE is trunk. access is implied.";
0346 }
0347 }
0348 else {
0349 /* */
0350 /* Process each Interface of the range. */
0351 /* This is accomplished by calling a recursive template. */
0352 /* */
0353 call ex-loop($maxcount = $tooct3, $initial-value = $fromoct3, $fromtype, $fromoct1, $fromoct2,$port-mode, $vlan, $vlan-id, $action, $trace, $set-loc, $description);
0354 /* See if the user wants the macro removed from the config. */
0355 call macro-attack($bitbucket);
0356 }
0357 }
0358 else {
0359 <xnm:error> {
0360 <message> {
0361 expr "RANGE ERROR: Invalid FROM ";
0362 expr $from;
0363 expr " or TO ";
0364 expr $to;
0365 expr " interface \n";
0366 }
0367 }
0368 }
0369 }
0370 }
0371
0372 /*
0373 * NAME: EX-LOOP
0374 * PURPOSE: To process each Interface in the range specified.
0375 * CALLED: Called if no errors where found with the input to the macro.
0376 * Also called recursively within itself. This is how looping works.
0377 *
0378 * PARMS PASSED:
0379 * $maxcount = It's the ending Interface number
0380 * Used for controlling the loop
0381 * $initial-value = It's the starting Interface number
0382 * Used for controlling the loop
0383 * $fromtype = Type of interface (GE or XE)
0384 * Used to reconstruct the full Interface name
0385 * $fromoct1 = The DPC (Member) number
0386 * Used to reconstruct the full Interface name
0387 * $fromoct2 = The PIC number
0388 * Used to reconstruct the full Interface name
0389 * $port-mode = If set to "trunk", then the "port-mode trunk" option
0390 * is added to the Interface
0391 * $vlan = The vlan name to add to the Interface
0392 * $vlan-id = The vlan-id for the vlan.
0393 * Currently not used
0394 * $action = If set to "delete", then kill-it is called
0395 * $trace = If "ztrace" is specified in the macro, then
0396 * print out debugging information
0397 * $set-loc = Instead of adding the vlan to the interface,
0398 * add the interface to the vlan.
0399 * $description = The "description" to set on each interface
0400 *
0401 */
0402 template ex-loop ($maxcount, $initial-value, $fromtype, $fromoct1, $fromoct2, $port-mode, $vlan, $vlan-id, $action, $trace, $set-loc, $description) {
0403
0404 if ($initial-value <= $maxcount) {
0405 var $ifl = $fromtype _ "-" _ $fromoct1 _ "/" _ $fromoct2 _ "/" _ $initial-value;
0406 /* */
0407 /* If debug was requested from the macro, then print out a message */
0408 /* for each interface being worked on. */
0409 /* */
0410 if (contains($trace,"ztrace")) {
0411 call write-msg($ifl, $port-mode, $vlan, $vlan-id, $action, $type = "ex", $set-loc);
0412 }
0413 if ($action == "delete" and not($set-loc == "setv")) {
0414 call kill-it-interfaces($ifl, $port-mode, $vlan);
0415 }
0416 else if ($action == "delete" and $set-loc == "setv") {
0417 call kill-it-vlans($ifl, $port-mode, $vlan);
0418 }
0419 else if ($set-loc == "setv") {
0420 call attach-to-vlans($ifl, $port-mode, $vlan, $description);
0421 }
0422 else {
0423 call attach-to-interfaces-ex($ifl, $port-mode, $vlan, $description);
0424 }
0425 call ex-loop($maxcount, $initial-value = $initial-value + 1, $fromtype, $fromoct1, $fromoct2,$port-mode, $vlan, $vlan-id, $action, $trace, $set-loc, $description);
0426 }
0427 }
0428
0429 /*
0430 * NAME: KILL-IT-INTERFACES
0431 * PURPOSE: To remove an element from the configuration.
0432 * CALLED: Only called if "action delete" is specified in the range macro
0433 * and if "setv" is NOT specified in the range macro
0434 *
0435 * PARMS PASSED:
0436 * $ifl = The interface name to act on
0437 * $port-mode = if "mode = trunk", then delete the <port-mode> element
0438 * $vlan = if "vlan" is non-blank, then delete the <members> element
0439 *
0440 * NOTE: If both $port-mode and $vlan are true, then both will be deleted.
0441 * If only $ifl is specified, then the complete interface is deleted
0442 *
0443 */
0444 template kill-it-interfaces($ifl, $port-mode, $vlan) {
0445 if (not($vlan) and not($port-mode)) {
0446 <change> {
0447 <interfaces> {
0448 <interface delete="delete"> {
0449 <name> $ifl;
0450 }
0451 }
0452 }
0453 }
0454 else {
0455 <change> {
0456 <interfaces> {
0457 <interface> {
0458 <name> $ifl;
0459 <unit> {
0460 <name> "0";
0461 <family> {
0462 <ethernet-switching> {
0463 if ($port-mode) {
0464 <port-mode delete="delete">;
0465 }
0466 if ($vlan) {
0467 <vlan> {
0468 <members delete="delete"> $vlan;
0469 }
0470 }
0471 }
0472 }
0473 }
0474 }
0475 }
0476 }
0477 }
0478 }
0479 /*
0480 * NAME: KILL-IT-VLANS
0481 * PURPOSE: To remove an element from the configuration.
0482 * CALLED: Only called if "action delete" is specified in the range macro
0483 * and if "setv" is specified in the range macro
0484 *
0485 * PARMS PASSED:
0486 * $ifl = The interface name to act on
0487 * $port-mode = if "mode = trunk", then delete the <port-mode> element
0488 * $vlan = if "vlan" is non-blank, then delete the Interface from the
0489 * VLANS hierarchy
0490 *
0491 * NOTE: If both $port-mode and $vlan are true, then both will be deleted.
0492 * If only $ifl is specified, then the complete interface is deleted
0493 *
0494 */
0495 template kill-it-vlans($ifl, $port-mode, $vlan) {
0496 if (not($vlan) and not($port-mode)) {
0497 <change> {
0498 <interfaces> {
0499 <interface delete="delete"> {
0500 <name> $ifl;
0501 }
0502 }
0503 }
0504 }
0505 else {
0506 <change> {
0507 <interfaces> {
0508 <interface> {
0509 <name> $ifl;
0510 <unit> {
0511 <name> "0";
0512 <family> {
0513 <ethernet-switching> {
0514 if ($port-mode) {
0515 <port-mode delete="delete">;
0516 }
0517 }
0518 }
0519 }
0520 }
0521 }
0522 }
0523 <change> {
0524 <vlans> {
0525 <vlan> {
0526 <name> $vlan;
0527 <interface delete="delete"> {
0528 <name> $ifl _ ".0";
0529 }
0530 }
0531 }
0532 }
0533
0534 }
0535 }
0536 /*
0537 * NAME: MACRO-ATTACK
0538 * PURPOSE: To remove the range macro from the configuration.
0539 * CALLED: Only called if "remove" is specified in the range macro
0540 *
0541 * PARMS PASSED:
0542 * $bitbucket = The name of the apply-macro to delete
0543
0544 */
0545 template macro-attack($bitbucket) {
0546 if (not($bitbucket == "")) {
0547 <change> {
0548 <apply-macro delete="delete"> {
0549 <name> $bitbucket;
0550 }
0551 }
0552 }
0553 }
0554
0555
0556 /*
0557 * NAME: WRITE-MSG
0558 * PURPOSE: Prints a Warning Message showing the CLI command that will be
0559 * applied to the configuration.
0560 * CALLED: Only called if "ztrace" is specified in the range macro
0561 *
0562 * PARMS PASSED:
0563 * $ifl = The interface name being acted on
0564 * $port-mode = "port-mode" specified in the macro
0565 * $vlan = "vlan" specified in the macro
0566 * $action = "action" specified in the macro
0567 * $set-loc = "setv" specified in the macro
0568 *
0569 *
0570 */
0571 template write-msg($ifl, $port-mode, $vlan, $vlan-id, $action, $type, $set-loc) {
0572 <xnm:warning> {
0573 <message> {
0574 expr "RANGE TRACE: ";
0575 if ($action == "delete") {
0576 expr "delete ";
0577 }
0578 else {
0579 expr "set ";
0580 }
0581 expr $ifl;
0582 if ($port-mode == "trunk" || $vlan and $type == "ex") {
0583 expr " unit 0 family ethernet-switching";
0584 if ($port-mode == "trunk") {
0585 expr " port-mode trunk";
0586 }
0587 if ($vlan) {
0588 expr " vlan members ";
0589 expr $vlan;
0590 expr " location ";
0591 expr $set-loc;
0592 }
0593 }
0594 if ($port-mode == "trunk" || $vlan-id and $type == "mx") {
0595 expr " unit 0 family bridge";
0596 if ($port-mode == "trunk") {
0597 expr " interface-mode trunk";
0598 expr " vlan-id-list ";
0599 expr $vlan-id;
0600 }
0601 else {
0602 expr " interface-mode access";
0603 expr " vlan-id ";
0604 expr $vlan-id;
0605 }
0606 }
0607 }
0608 }
0609 }
0610 /*
0611 * NAME: ATTACH-INTERFACES-EX
0612 * PURPOSE: Build the XML statement needed to add the information to
0613 * the Interfaces heirarchy
0614 * CALLED: Only called if "setv" is NOT specified in the range macro
0615 * for EX-series devices
0616 *
0617 * PARMS PASSED:
0618 * $ifl = The interface name being acted on
0619 * $port-mode = "port-mode" specified in the macro
0620 * $vlan = "vlan" specified in the macro
0621 * $description = "description" specified in the macro
0622 *
0623 *
0624 */
0625 template attach-to-interfaces-ex($ifl, $port-mode, $vlan, $description) {
0626 <change> {
0627 <interfaces> {
0628 <interface> {
0629 <name> $ifl;
0630 if ($description) {
0631 <description> $description;
0632 }
0633 <unit> {
0634 <name> "0";
0635 <family> {
0636 <ethernet-switching> {
0637 if ($port-mode == "trunk") {
0638 <port-mode> "trunk";
0639 }
0640 <vlan> {
0641 <members> $vlan;
0642 }
0643 }
0644 }
0645 }
0646 }
0647 }
0648 }
0649 }
0650
0651 /*
0652 * NAME: ATTACH-VLANS
0653 * PURPOSE: Build the XML statement needed to add the information to
0654 * the VLANS heirarchy
0655 * CALLED: Only called if "setv" is specified in the range macro
0656 *
0657 * PARMS PASSED:
0658 * $ifl = The interface name being acted on
0659 * $port-mode = "port-mode" specified in the macro
0660 * $vlan = "vlan" specified in the macro
0661 * $description = "description" specified in the macro
0662 *
0663 *
0664 */
0665 template attach-to-vlans($ifl, $port-mode, $vlan, $description) {
0666 <change> {
0667 <vlans> {
0668 <vlan> {
0669 <name> $vlan;
0670 <interface> {
0671 <name> $ifl;
0672 }
0673 }
0674 }
0675 }
0676 <change> {
0677 <interfaces> {
0678 <interface> {
0679 <name> $ifl;
0680 if ($description) {
0681 <description> $description;
0682 }
0683 <unit> {
0684 <name> "0";
0685 <family> {
0686 <ethernet-switching> {
0687 if ($port-mode == "trunk") {
0688 <port-mode> "trunk";
0689 }
0690 }
0691 }
0692 }
0693 }
0694 }
0695 }
0696 }
0697
0698 /******************************************************************/
0699 /* */
0700 /* MX Specific Templates */
0701 /* */
0702 /******************************************************************/
0703 template mx-main {
0704
0705 /*
0706 * Process the apply-macros
0707 * Only look at macros that start with "range"
0708 *
0709 */
0710 for-each (apply-macro[starts-with(name,"range")]) {
0711 var $vlan = data[name = 'vlan']/value;
0712 var $vlan-id = data[name = 'vlan-id']/value;
0713 var $from = data[name = 'from']/value;
0714 var $to = data[name = 'to']/value;
0715 var $action = data[name = 'action']/value;
0716 var $port-mode = data[name = 'port-mode']/value;
0717 var $fromtype = substring-before($from,'-');
0718 var $totype = substring-before($to,'-');
0719 var $description = data[name = 'description']/value;
0720 /* check to see if macro should be delete on successful commit */
0721 var $bitbucket = { if (data[name = 'remove']) {
0722 expr name;
0723 }
0724 else {
0725 expr "";
0726 }
0727 }
0728 /* check to see if macro tracing was turned on */
0729 var $trace = { if (data[name = 'ztrace']) {
0730 expr "ztrace";
0731 }
0732 else {
0733 expr "";
0734 }
0735 }
0736 /* check to see if set location was turned on */
0737 if (data[name = 'setv']) {
0738 <xnm:warning> {
0739 <message> "RANGE MACRO: option SETV is not supported on the MX-series.";
0740 }
0741 }
0742 if (not($fromtype =='') and not($totype =='') and $fromtype == $totype and ($fromtype == "ge" ||$fromtype == "xe") and ($totype == "ge" || $totype == "xe")) {
0743
0744 /* Split up the Interfaces into DPC, PIC, PORT */
0745
0746 var $fromtriple = substring-after($from,'-');
0747 var $fromoct1 = substring-before($fromtriple,'/');
0748 var $fromleft = substring-after($fromtriple,'/');
0749 var $fromoct2 = substring-before($fromleft,'/');
0750 var $fromoct3 = substring-after($fromleft,'/');
0751 var $totriple = substring-after($to,'-');
0752 var $tooct1 = substring-before($totriple,'/');
0753 var $toleft = substring-after($totriple,'/');
0754 var $tooct2 = substring-before($toleft,'/');
0755 var $tooct3 = substring-after($toleft,'/');
0756
0757 /* Validate the information supplied in the macro */
0758 /* */
0759 if (not($fromoct1) || not($fromoct2) || not($fromoct3) || not($tooct1) || not($tooct2) || not($tooct3)) {
0760 <xnm:error> {
0761 <message> "RANGE ERROR: Invalid Interface Format";
0762 }
0763 }
0764 else if (not($fromoct1 == $tooct1)) {
0765 <xnm:error> {
0766 <message> "RANGE ERROR: From DPC != To DPC";
0767 }
0768 }
0769 else if ($fromoct1 == $tooct1 and $fromoct2 > $tooct2) {
0770 <xnm:error> {
0771 <message> "RANGE ERROR: From PIC >= To PIC on same DOC";
0772 }
0773 }
0774 else if ($fromoct1 == $tooct1 and $fromoct2 == $tooct2 and $fromoct3 >= $tooct3) {
0775 <xnm:error> {
0776 <message> "RANGE ERROR: From Port >= To Port on same DPC/PIC";
0777 }
0778 }
0779 else if ($fromoct1 > 7 || $tooct1 > 7) {
0780 <xnm:error> {
0781 <message> "RANGE ERROR: DPC must be 0 to 7";
0782 }
0783 }
0784 else if (not($vlan-id) and not($port-mode) and not($action)) {
0785 <xnm:error> {
0786 <message> "RANGE ERROR: Macro MUST include a vlan-id and/or MODE";
0787 }
0788 }
0789 else if ($action and not($action == "delete")) {
0790 <xnm:error> {
0791 <message> "RANGE ERROR: Valid ACTION is delete. set is implied.";
0792 }
0793 }
0794 else if ($port-mode and not($port-mode == "trunk")) {
0795 <xnm:error> {
0796 <message> "RANGE ERROR: Valid MODE is trunk. access is implied.";
0797 }
0798 }
0799 else {
0800 /* If the vlan doesn't exist, create it and add the vlan-id */
0801 /* The vlan is created to avoid warning messages on the commit. */
0802 /* Putting a vlan on an Interface without the vlan existing in */
0803 /* vlans, causes the warning. */
0804 if ($vlan and not($action == "delete")) {
0805 <change> {
0806 <bridge-domains> {
0807 <domain> {
0808 <name> $vlan;
0809 <vlan-id> $vlan-id;
0810 }
0811 }
0812 }
0813 }
0814 /* */
0815 /* Process each Interface of the range. */
0816 /* This is accomplished by calling a recursive template. */
0817 /* */
0818 call mx-loop-outside($maxcount = $tooct3, $initial-value = $fromoct3, $fromtype, $fromoct1,$str-pic = $fromoct2, $end-pic = $tooct2, $tooct3, $port-mode, $vlan, $vlan-id, $action, $trace,$description);
0819 /* See if the user wants the macro removed from the config. */
0820 call macro-attack($bitbucket);
0821 }
0822 }
0823 else {
0824 <xnm:error> {
0825 <message> {
0826 expr "RANGE ERROR: Invalid FROM ";
0827 expr $from;
0828 expr " or TO ";
0829 expr $to;
0830 expr " interface \n";
0831 }
0832 }
0833 }
0834 }
0835 }
0836 /*
0837 * NAME: MX-LOOP-OUTSIDE
0838 * PURPOSE: To process each Interface in the range specified.
0839 * CALLED: Called if no errors where found with the input to the macro.
0840 * Also called recursively within itself. This is how looping works.
0841 *
0842 * PARMS PASSED:
0843 * $maxcount = It's the ending Interface number
0844 * Used for controlling the loop
0845 * $initial-value = It's the starting Interface number
0846 * Used for controlling the loop
0847 * $fromtype = Type of interface (GE or XE)
0848 * Used to reconstruct the full Interface name
0849 * $fromoct1 = The DPC (Member) number
0850 * Used to reconstruct the full Interface name
0851 * $str-pic = The PIC number to start on
0852 * Used to reconstruct the full Interface name
0853 * $end-pic = The PIC number to end on
0854 * Used to reconstruct the full Interface name
0855 * $tooct3 = The Interface number to end on
0856 * Used to reconstruct the full Interface name
0857 * $port-mode = If set to "trunk", then the "port-mode trunk" option
0858 * is added to the Interface
0859 * $vlan = The vlan name to add to the Interface
0860 * $vlan-id = The vlan-id for the vlan.
0861 * Currently not used
0862 * $action = If set to "delete", then kill-it is called
0863 * $trace = If "ztrace" is specified in the macro, then
0864 * print out debugging information
0865 * $description = The "description" to add to each Interface.
0866 *
0867 */
0868 template mx-loop-outside ($maxcount, $initial-value, $fromtype, $fromoct1, $str-pic, $end-pic, $tooct3,$port-mode, $vlan, $vlan-id, $action, $trace, $description) {
0869 /* */
0870 /* To cross PICs, nested loops must be used and both */
0871 /* loops must be recursive. */
0872 /* */
0873 if ($str-pic = $end-pic) {
0874 call mx-loop-inside ($maxcount = $tooct3, $initial-value, $fromtype, $fromoct1, $str-pic, $end-pic,$tooct3, $port-mode, $vlan, $vlan-id, $action, $trace, $description);
0875 }
0876 else if ($str-pic < $end-pic and $fromtype == "ge") {
0877 call mx-loop-inside ($maxcount = 9, $initial-value, $fromtype, $fromoct1, $str-pic, $end-pic,$tooct3, $port-mode, $vlan, $vlan-id, $action, $trace, $description);
0878 call mx-loop-outside ($maxcount, $initial-value = 0, $fromtype, $fromoct1, $str-pic = $str-pic + 1,$end-pic, $tooct3, $port-mode, $vlan, $vlan-id, $action, $trace, $description);
0879 }
0880 else if ($str-pic < $end-pic and $fromtype == "xe") {
0881 call mx-loop-inside ($maxcount = 1, $initial-value, $fromtype, $fromoct1, $str-pic, $end-pic,$tooct3, $port-mode, $vlan, $vlan-id, $action, $trace, $description);
0882 call mx-loop-outside ($maxcount, $initial-value = 0, $fromtype, $fromoct1, $str-pic = $str-pic + 1,$end-pic, $tooct3, $port-mode, $vlan, $vlan-id, $action, $trace, $description);
0883 }
0884
0885 }
0886 /*
0887 * NAME: MX-LOOP-INSIDE
0888 * PURPOSE: To process each Interface in the range specified.
0889 * CALLED: Called if no errors where found with the input to the macro.
0890 * Also called recursively within itself. This is how looping works.
0891 *
0892 * PARMS PASSED:
0893 * $maxcount = It's the ending Interface number
0894 * Used for controlling the loop
0895 * $initial-value = It's the starting Interface number
0896 * Used for controlling the loop
0897 * $fromtype = Type of interface (GE or XE)
0898 * Used to reconstruct the full Interface name
0899 * $fromoct1 = The DPC (Member) number
0900 * Used to reconstruct the full Interface name
0901 * $str-pic = The PIC number to start on
0902 * Used to reconstruct the full Interface name
0903 * $end-pic = The PIC number to end on
0904 * Used to reconstruct the full Interface name
0905 * $tooct3 = The Interface number to end on
0906 * Used to reconstruct the full Interface name
0907 * $port-mode = If set to "trunk", then the "port-mode trunk" option
0908 * is added to the Interface
0909 * $vlan = The vlan name to add to the Interface
0910 * $vlan-id = The vlan-id for the vlan.
0911 * Currently not used
0912 * $action = If set to "delete", then kill-it is called
0913 * $trace = If "ztrace" is specified in the macro, then
0914 * print out debugging information
0915 * $description = The "description" to add to each Interface.
0916 *
0917 */
0918 template mx-loop-inside ($maxcount, $initial-value, $fromtype, $fromoct1, $str-pic, $end-pic, $tooct3,$port-mode, $vlan, $vlan-id, $action, $trace, $description){
0919 if ($initial-value <= $maxcount) {
0920 var $ifl = $fromtype _ "-" _ $fromoct1 _ "/" _ $str-pic _ "/" _ $initial-value;
0921 /* */
0922 /* If debug was requested from the macro, then print out a message */
0923 /* for each interface being worked on. */
0924 /* */
0925 if (contains($trace,"ztrace")) {
0926 call write-msg($ifl, $port-mode, $vlan, $vlan-id, $action, $type = "mx", $set-loc);
0927 }
0928 if ($action == "delete") {
0929 call kill-it-interfaces-mx($ifl, $port-mode, $vlan-id);
0930 }
0931 else {
0932 call attach-to-interfaces-mx($ifl, $port-mode, $vlan-id, $description);
0933 }
0934
0935 call mx-loop-inside ($maxcount, $initial-value = $initial-value + 1, $fromtype, $fromoct1, $str-pic, $end-pic, $tooct3, $port-mode, $vlan, $vlan-id, $action, $trace, $description);
0936 }
0937 }
0938
0939 /*
0940 * NAME: KILL-IT-INTERFACES-MX
0941 * PURPOSE: To remove an element from the configuration.
0942 * CALLED: Only called if "action delete" is specified in the range macro
0943 *
0944 * PARMS PASSED:
0945 * $ifl = The interface name to act on
0946 * $port-mode = if "mode = trunk", then delete the <port-mode> element
0947 * $vlan-id = if "vlan-id" is non-blank, then delete the <vlan-id> element
0948 * or <vlan-id-list> element depending on $port-mode.
0949 *
0950 * NOTE: If both $port-mode and $vlan-ld are true, then both will be deleted.
0951 * If only $ifl is specified, then the complete interface is deleted
0952 *
0953 */
0954 template kill-it-interfaces-mx($ifl, $port-mode, $vlan-id) {
0955 if (not($vlan-id) and not($port-mode)) {
0956 <change> {
0957 <interfaces> {
0958 <interface delete="delete"> {
0959 <name> $ifl;
0960 }
0961 }
0962 }
0963 }
0964 else {
0965 <change> {
0966 <interfaces> {
0967 <interface> {
0968 <name> $ifl;
0969 <unit> {
0970 <name> "0";
0971 if ($vlan-id and $port-mode) {
0972 if(count(../interfaces/interface[name=$ifl]/unit[name="0"]/family/bridge/vlan-id-list) == 1) {
0973 /* */
0974 /* If only 1 vlan-id is on the trunk */
0975 /* the whole family needs to be removed */
0976 /* or else the "commit" will fail since */
0977 /* the trunk will have no vlans on it */
0978 /* */
0979 <family delete="delete"> {
0980 <bridge>;
0981 }
0982 }
0983 else {
0984 <family> {
0985 <bridge> {
0986 <vlan-id-list delete="delete"> $vlan-id;
0987 }
0988 }
0989 }
0990 }
0991 /* */
0992 /* If not a trunk and the vlan-id is being */
0993 /* deleted, then we must remove the own family */
0994 /* or else the "commit" will fail since */
0995 /* "family bridge" with an "interface-mode" */
0996 /* of "access" must have a vlan-id on it. */
0997 /* */
0998 else if ($vlan-id) {
0999 <family delete="delete"> {
1000 <bridge>;
1001 }
1002 }
1003 }
1004 }
1005 }
1006 }
1007 }
1008 }
1009 /*
1010 * NAME: ATTACH-INTERFACES-MX
1011 * PURPOSE: Build the XML statement needed to add the information to
1012 * the Interfaces heirarchy
1013 * CALLED: Only called for MX-series devices
1014 *
1015 * PARMS PASSED:
1016 * $ifl = The interface name being acted on
1017 * $port-mode = "port-mode" specified in the macro
1018 * $vlan = "vlan" specified in the macro
1019 * $description = "description" specified in the macro
1020 *
1021 *
1022 */
1023 template attach-to-interfaces-mx($ifl, $port-mode, $vlan-id, $description) {
1024 /*
1025 * Verify that the the interface we are working is on suitable.
1026 * If the interface exists, determine if "family bridge" is
1027 * already set. If not, then print a warning and do not
1028 * apply any macro settings.
1029 *
1030 */
1031 var $u-count=count(../interfaces/interface[name = $ifl]/unit);
1032 var $f-count=count(../interfaces/interface[name = $ifl]/unit[name="0"]/family);
1033 if ($u-count > 1 || $f-count > 1 || (not(../interfaces/interface[name = $ifl]/unit[name ="0"]/family/bridge) and $f-count = 1)) {
1034 <xnm:warning> {
1035 <message> {
1036 expr "RANGE MACRO: Conflict on Interface ";
1037 expr $ifl;
1038 expr ". Unable to apply macro to the interface.";
1039 }
1040 }
1041 }
1042 else {
1043 <change> {
1044 <interfaces> {
1045 <interface> {
1046 <name> $ifl;
1047 if ($description) {
1048 <description> $description;
1049 }
1050 <unit> {
1051 <name> "0";
1052 <family> {
1053 <bridge> {
1054 /* */
1055 /* Trunks on MX do not support "vlan-id" so */
1056 /* make sure to write into "vlan-id-list" */
1057 /* */
1058 if ($port-mode == "trunk") {
1059 <interface-mode> "trunk";
1060 <vlan-id-list> $vlan-id;
1061 }
1062 else {
1063 /* */
1064 /* MX does not assume a port is of type */
1065 /* access, so we must set the type when */
1066 /* we set the vlan-id or the commit will */
1067 /* fail. */
1068 /* */
1069 <interface-mode> "access";
1070 <vlan-id> $vlan-id;
1071 }
1072 }
1073 }
1074 }
1075 }
1076 }
1077 }
1078 }
1079 }