Community discussions

MikroTik App
 
User avatar
kehrlein
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 60
Joined: Tue Jul 09, 2019 1:35 am

Script for setting Locally Administered MAC Address on bridges

Sun Jul 14, 2024 2:06 pm

MikroTik recommends manually setting MAC addresses on bridges using "admin-mac" (see https://wiki.mikrotik.com/wiki/Manual:Interface/Bridge).
To avoid unwanted MAC address changes, Locally Administered Addresses (https://en.wikipedia.org/wiki/MAC_addre ... ed_address) can be used.

Here's a script to automatically set the MAC of all configured bridges based on the hardware MAC address of ether1:
:local locAdmMac
:local originalMacAddress [/interface get [find where name=ether1] mac-address]
:local bridges [/interface bridge find]
:local macCounter 1

:put ("Original MAC of ether1: " . $originalMacAddress . "\n")

:foreach bridge in=$bridges do={
   :local bridgeName ([/interface get $bridge name])
   :local newMacAddress ""
   :set locAdmMac ([:pick $originalMacAddress 0 1] . "2" . [:pick $originalMacAddress 2 15])

   :if ( [ :len $macCounter; ] = 1 ) do={ :set macCounter  ("0" . $macCounter) }

   :set  newMacAddress ($locAdmMac.$macCounter)
   :put ("New MAC for " . $bridgeName . ":    " .  $newMacAddress)
    /interface/bridge/set $bridge auto-mac=no admin-mac=$newMacAddress

   :set macCounter ($macCounter + 1)
}


I appreciate feedback and improvement suggestions.
Last edited by kehrlein on Mon Jul 15, 2024 6:51 pm, edited 1 time in total.
 
Apachez
Member Candidate
Member Candidate
Posts: 168
Joined: Mon Jul 01, 2024 11:45 pm

Re: Script for setting Locally Administered MAC Address on bridges

Sun Jul 14, 2024 3:58 pm

You can see how Mikrotik prefer to set it using "/system/default-configuration/script/print" (example below is from 7.15.2 stable):

/interface bridge
  add name=bridge disabled=no auto-mac=yes protocol-mode=rstp comment=defconf;
:local bMACIsSet 0;
:foreach k in=[/interface find where !(slave=yes   || passthrough=yes || type=loopback || name~"bridge")] do={
  :local tmpPortName [/interface get $k name];
  :if ($bMACIsSet = 0) do={
    :if ([/interface get $k type] = "ether") do={
      /interface bridge set "bridge" auto-mac=no admin-mac=[/interface get $tmpPortName mac-address];
      :set bMACIsSet 1;
    }
  }
}

Here is how I wrote the above in my script (basically the same - the examples below are just snippets):

#
# Setting variables
#
:global myMSTPREGION "TEST";
:global myMSTPREVISION "1";
:global myMSTPIDENTIFIER "1";
:global myMSTPPRIORITY "0x8000";
:global myFOUND "0";
#
# Function to display and log messages
#
:global debugMSG do={
    :put "DEBUG: $1";
    :log info "DEBUG: $1";
}
#
# Applying configuration
#
$debugMSG ("Applying custom configuration...");
/interface bridge add arp-timeout=4m auto-mac=yes disabled=no forward-delay=4s frame-types=admit-only-vlan-tagged max-message-age=6s name=bridge1 priority=0 protocol-mode=mstp region-name=$myMSTPREGION region-revision=$myMSTPREVISION transmit-hold-count=1 vlan-filtering=yes
#
# Setting static mac-address on bridge1 if ether interface is found
#
:set myFOUND 0;
:foreach i in=[/interface find where !(slave=yes || passthrough=yes || type=loopback || name~"bridge")] do={
    :local tmpPORTNAME [/interface get $i name];
    :if ($myFOUND = 0) do={
        :if ([/interface get $i type] = "ether") do={
            :local tmpMAC [/interface get $tmpPORTNAME mac-address];
            $debugMSG ("Set bridge1 admin-mac: ".$tmpMAC);
            /interface bridge set bridge1 auto-mac=no admin-mac=$tmpMAC;
            :set myFOUND 1;
        }
    }
}

The concept of above is to first set the auto-mac=yes and then loop through available interfaces until you find someone suitable to grab its MAC-address and if that happens set auto-mac=no at the same time. The myFOUND variable is so only the first found MAC-address will be used to set the MAC-address statically.

This way if the loop fails to find a MAC-address to be used you still have your bridge with auto-mac=yes setup correctly.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 13149
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 12:02 pm

To avoid address conflicts

FALSE: Phrased that way the sentence is misleading.

It says exactly:
To avoid unwanted MAC address changes

Manually setting the MAC of one interface that is later removed from the bridge to, perhaps, put it on another: This creates conflicts...
Or load the backup or export onto another device: This creates conflicts...
 
Apachez
Member Candidate
Member Candidate
Posts: 168
Joined: Mon Jul 01, 2024 11:45 pm

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 12:35 pm

Speaking of conflicts... how come the original script form Mikrotik picks one of the physical interfaces MAC-address and put it on the bridge - wouldnt this cause a conflict aswell?
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 13149
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 1:29 pm

And why should it cause it?

The MikroTik script is intended for an unconfigured device, to which the script is applying the default configuration.
 
jaclaz
Forum Guru
Forum Guru
Posts: 3115
Joined: Tue Oct 03, 2023 4:21 pm

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 1:54 pm

Re the script in the first post, the default configuration on most (at least SoHo) devices, should be with ether1 outside of the bridge (WAN) and all the other posts added to the bridge (LAN), so choosing the ether1 address and assigning it to the bridge is actually guaranteed to create a collision on many devices.

Question is how are the (automatic) MAC addresses of the single ports generated?

I think they have a "common base" (however it is calculated) and then they are sequential, so it could be a good idea, on a 5 port device to generate the MAC address for the bridge as the 6th number, on a 8 port device as the 9th, etc.? :?:
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 13149
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 2:17 pm

An excerpt of the autoconfiguration script that I use on CERTAIN devices....

excerpt code

[…]
:global GconnEth "ether1"
[…]
/int bridge
add name=bri-lan […]
[…]
/int bridge port
:foreach interfacciaTest in=[/int ethernet find where name!=$GconnEth] do={add bridge=bri-lan interface=$interfacciaTest}
[…]
/int bridge
set bri-lan admin-mac=[/int ethernet get [/int bri port get ([find where name=bri-lan]->0) interface] mac-address] auto-mac=no
[…]
Generally speaking, in bridges it is always better to use the "smallest" one of the REAL interfaces as the MAC.
Then if there aren't any real ones, you choose according to your taste...
 
jaclaz
Forum Guru
Forum Guru
Posts: 3115
Joined: Tue Oct 03, 2023 4:21 pm

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 2:42 pm

Generally speaking, in bridges it is always better to use the "smallest" one of the REAL interfaces as the MAC.
Why?
I mean, is there a technical reason, or is just the tradition (like ether1 is always "boot" and - on certain devices - "internet" or WAN)?
If it is better (there is some technical reason for this) to have a "low" number for the bridge must it be the same of an existing "direct" port?
It still seems to me likely to create a collision.
Example for a 4 port device:
ether1 ::::01 <- single port out of the bridge
ether2 ::::02 <- lower port part of the bridge
ether3 ::::03 <-another port part of the bridge
ether4 ::::04 <- yet another port part of the bridge

The bridge should be assigned the same address as ether2, ::::02.

Then, for whatever reason, if/when the ether2 is taken out of the bridge it will create a collision.

If the bridge is instead assigned a higher number, ::::05 there are no ports with the same number, so you can take out of the bridge any of ether2, 3 or 4 without any risk.
 
Apachez
Member Candidate
Member Candidate
Posts: 168
Joined: Mon Jul 01, 2024 11:45 pm

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 2:45 pm

And why should it cause it?

The MikroTik script is intended for an unconfigured device, to which the script is applying the default configuration.

Because the original script will pick any interface which isnt a slave, passthrough, loopback or contains the name "*bridge*" and if such interface is type ether its MAC-address will be duplicated onto the bridge.

Which means its highly likely that it will pick up ether1 which often is the MGMT interface but if such doesnt exist then its the first interface on the switchchip (like on a 8 port CRS112).

This gives that you will now have 2 interfaces with the same MAC-address - the physical ether1 (whoever that is regarding MGMT interface vs regular switch interface) AND the bridge itself.

This "should normally" not be an issue but will be if the bridge AND whatever interface got picked to have its MAC-address duplicated and both are connected to the same VLAN.

For example you connect any of int2-8 of this CRS112 to another switch and to the same switch also connect int1 (which you use for management) and surprise...
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 13149
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 4:33 pm

Generally speaking, in bridges it is always better to use the "smallest" one of the REAL interfaces as the MAC.
Why?
I mean, is there a technical reason [...]
OBVIOUSLY we mean real interfaces in the bridge, not others not in the bridge...

From a technical point of view, there are more experts,
but + or - it is the same reason why if an interface has 2 IP addresses (and the rest of the configuration allows it)
the device will use the IP with the smallest absolute value .
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 13149
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 4:35 pm

ether1 which often is the MGMT interface
On what brand?

I never see ether1 as management interface on MikroTik product (on DEFAULT configuration, OBVIOUSLY).
(or at least I've never seen one directly before)

So the ORIGINAL MikroTik script for the default configuration does what it should.
If you don't like how it's configured, you take the risk of changing the configuration, and knowing what you are doing...


The true defconf script is more complex from what you see from "print".....
Display more than what you report before...

excerpt from defconf original code

    :if ($lanPort = "bridge") do={
      #bridge all interfaces that are not wan or slave ports
      $addCL (" /interface bridge")
      $addCL ("   add name=$lanPort disabled=no auto-mac=yes protocol-mode=rstp comment=defconf;")
      $addCL (" :local bMACIsSet 0;")
      $addDCL ("\$[:tostr [/interface print as-value]]")
      :local excWlans "";
      :if ($hasCapsMan > 0) do={
        :set excWlans "|| name=wlan1 || name=wlan2"
      }
      :if ($wanPorts!="") do={
        :local tmpWanPorts "";
        :foreach i in=$wanPorts do={
          :set tmpWanPorts "$tmpWanPorts || name=\"$i\"";
        }
        $addCL (" :foreach k in=[/interface find where !(slave=yes $excWlans $tmpWanPorts || passthrough=yes || type=loopback || name~\"$lanPort\")] do={")
      } else={
        $addCL (" :foreach k in=[/interface find where !(slave=yes $excWlans)] do={")
      }
      $addCL ("   :local tmpPortName [/interface get \$k name];")
      $printDebug ($tmpPortName)
      $addDCL ("add bridge port: \$tmpPortName")
      $addCL ("   :if (\$bMACIsSet = 0) do={")
      $addDCL ("\$[/interface get \$k type]")
      $addCL ("     :if ([/interface get \$k type] = \"ether\") do={")
      $addDCL ("\$[/interface get \$tmpPortName mac-address]")
      $addCL ("       /interface bridge set \"$lanPort\" auto-mac=no admin-mac=[/interface get \$tmpPortName mac-address];")
      $addCL ("       :set bMACIsSet 1;")
      $addCL ("     }")
      $addCL ("   }")
      $addCL ("     :if (([/interface get \$k type] != \"ppp-out\") && ([/interface get \$k type] != \"lte\")) do={")
      $addCL ("       /interface bridge port")
      $addCL ("         add bridge=$lanPort interface=\$tmpPortName comment=defconf;")
      $addCL ("     }")
      $addCL ("   }")
    }
 
User avatar
kehrlein
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 60
Joined: Tue Jul 09, 2019 1:35 am

Re: Script for setting Locally Administered MAC Address on bridges

Mon Jul 15, 2024 6:50 pm

To avoid address conflicts
FALSE: Phrased that way the sentence is misleading.

It says exactly:
To avoid unwanted MAC address changes

You're right! I corrected it in the original post.
 
Apachez
Member Candidate
Member Candidate
Posts: 168
Joined: Mon Jul 01, 2024 11:45 pm

Re: Script for setting Locally Administered MAC Address on bridges

Tue Jul 16, 2024 12:15 am

ether1 which often is the MGMT interface
On what brand?

I never see ether1 as management interface on MikroTik product (on DEFAULT configuration, OBVIOUSLY).
(or at least I've never seen one directly before)

So the ORIGINAL MikroTik script for the default configuration does what it should.
If you don't like how it's configured, you take the risk of changing the configuration, and knowing what you are doing...


The true defconf script is more complex from what you see from "print".....
Display more than what you report before...

excerpt from defconf original code

    :if ($lanPort = "bridge") do={
      #bridge all interfaces that are not wan or slave ports
      $addCL (" /interface bridge")
      $addCL ("   add name=$lanPort disabled=no auto-mac=yes protocol-mode=rstp comment=defconf;")
      $addCL (" :local bMACIsSet 0;")
      $addDCL ("\$[:tostr [/interface print as-value]]")
      :local excWlans "";
      :if ($hasCapsMan > 0) do={
        :set excWlans "|| name=wlan1 || name=wlan2"
      }
      :if ($wanPorts!="") do={
        :local tmpWanPorts "";
        :foreach i in=$wanPorts do={
          :set tmpWanPorts "$tmpWanPorts || name=\"$i\"";
        }
        $addCL (" :foreach k in=[/interface find where !(slave=yes $excWlans $tmpWanPorts || passthrough=yes || type=loopback || name~\"$lanPort\")] do={")
      } else={
        $addCL (" :foreach k in=[/interface find where !(slave=yes $excWlans)] do={")
      }
      $addCL ("   :local tmpPortName [/interface get \$k name];")
      $printDebug ($tmpPortName)
      $addDCL ("add bridge port: \$tmpPortName")
      $addCL ("   :if (\$bMACIsSet = 0) do={")
      $addDCL ("\$[/interface get \$k type]")
      $addCL ("     :if ([/interface get \$k type] = \"ether\") do={")
      $addDCL ("\$[/interface get \$tmpPortName mac-address]")
      $addCL ("       /interface bridge set \"$lanPort\" auto-mac=no admin-mac=[/interface get \$tmpPortName mac-address];")
      $addCL ("       :set bMACIsSet 1;")
      $addCL ("     }")
      $addCL ("   }")
      $addCL ("     :if (([/interface get \$k type] != \"ppp-out\") && ([/interface get \$k type] != \"lte\")) do={")
      $addCL ("       /interface bridge port")
      $addCL ("         add bridge=$lanPort interface=\$tmpPortName comment=defconf;")
      $addCL ("     }")
      $addCL ("   }")
    }

On the Mikrotik brand.

The ether1 MAC-address have been selected by the DEFAULT script when setting the MAC-address for the bridge on all CRS models.

I can paste the full default script being used in 7.15.2 but that sets other parameters aswell not relevant for this thread who is about the MAC-address chosen for the bridge if/when auto-mac=no is being used.

You will see the result of this script when running "/system reset-configuration keep-users=yes no-defaults=no skip-backup=yes" or if you just do this in the CLI: "/system/default-configuration/script/print" (as I posted previously) to see the content of what this script is actually doing when you have "no-defaults=no" for reset-configuration.
 
Apachez
Member Candidate
Member Candidate
Posts: 168
Joined: Mon Jul 01, 2024 11:45 pm

Re: Script for setting Locally Administered MAC Address on bridges

Tue Jul 16, 2024 12:20 am

For reference here is the full default script being used by Mikrotik in 7.15.2 stable when you run a reset-configuration and have "no-defaults=no" being set:

[admin@Mikrotik] > /system/default-configuration/script/print without-paging 
  script: #| Welcome to RouterOS!
          #|    1) Set a strong router password in the System > Users menu
          #|    2) Upgrade the software in the System > Packages menu
          #|    3) Enable firewall on untrusted networks
          #| -----------------------------------------------------------------------------
          #| Switch mode:
          #|  * all interfaces switched;
          #| LAN Configuration:
          #| Login
          #|     admin user protected by password
          
          :global defconfMode;
          :log info "Starting defconf script";
          #-------------------------------------------------------------------------------
          # Apply configuration.
          # these commands are executed after installation or configuration reset
          #-------------------------------------------------------------------------------
          :if ($action = "apply") do={
            # wait for interfaces
            :local count 0;
            :while ([/interface ethernet find] = "") do={
              :if ($count = 30) do={
                :log warning "DefConf: Unable to find ethernet interfaces";
                /quit;
              }
              :delay 1s; :set count ($count +1); 
            };
           /interface bridge
             add name=bridge disabled=no auto-mac=yes protocol-mode=rstp comment=defconf;
           :local bMACIsSet 0;
           :foreach k in=[/interface find where !(slave=yes   || passthrough=yes || type=loopback || name~"bridge")] do={
             :local tmpPortName [/interface get $k name];
             :if ($bMACIsSet = 0) do={
               :if ([/interface get $k type] = "ether") do={
                 /interface bridge set "bridge" auto-mac=no admin-mac=[/interface get $tmpPortName mac-address];
                 :set bMACIsSet 1;
               }
             }
               :if (([/interface get $k type] != "ppp-out") && ([/interface get $k type] != "lte")) do={
                 /interface bridge port
                   add bridge=bridge interface=$tmpPortName comment=defconf;
               }
             }
            /ip address add address=192.168.88.1/24 interface=bridge comment="defconf";
           :if (!($keepUsers = "yes")) do={
             :if (!($defconfPassword = "" || $defconfPassword = nil)) do={
               /user set admin password=$defconfPassword
               :delay 0.5
               /user expire-password admin 
             }
           }
          }
          #-------------------------------------------------------------------------------
          # Revert configuration.
          # these commands are executed if user requests to remove default configuration
          #-------------------------------------------------------------------------------
          :if ($action = "revert") do={
           :if (!($keepUsers = "yes")) do={
             /user set admin password=""
             :delay 0.5
             /user expire-password admin 
           }
           /ip firewall filter remove [find comment~"defconf"]
           /ipv6 firewall filter remove [find comment~"defconf"]
           /ipv6 firewall address-list remove [find comment~"defconf"]
           /ip firewall nat remove [find comment~"defconf"]
           /interface list member remove [find comment~"defconf"]
           /interface detect-internet set detect-interface-list=none
           /interface detect-internet set lan-interface-list=none
           /interface detect-internet set wan-interface-list=none
           /interface detect-internet set internet-interface-list=none
           /interface list remove [find comment~"defconf"]
           /tool mac-server set allowed-interface-list=all
           /tool mac-server mac-winbox set allowed-interface-list=all
           /ip neighbor discovery-settings set discover-interface-list=!dynamic
             :local o [/ip dhcp-server network find comment="defconf"]
             :if ([:len $o] != 0) do={ /ip dhcp-server network remove $o }
             :local o [/ip dhcp-server find name="defconf" !disabled]
             :if ([:len $o] != 0) do={ /ip dhcp-server remove $o }
             /ip pool {
               :local o [find name="default-dhcp" ranges=192.168.88.10-192.168.88.254]
               :if ([:len $o] != 0) do={ remove $o }
             }
             :local o [/ip dhcp-client find comment="defconf"]
             :if ([:len $o] != 0) do={ /ip dhcp-client remove $o }
           /ip dns {
             set allow-remote-requests=no
             :local o [static find comment="defconf"]
             :if ([:len $o] != 0) do={ static remove $o }
           }
           /ip address {
             :local o [find comment="defconf"]
             :if ([:len $o] != 0) do={ remove $o }
           }
           :foreach iface in=[/interface ethernet find] do={
             /interface ethernet set $iface name=[get $iface default-name]
           }
           /interface bridge port remove [find comment="defconf"]
           /interface bridge remove [find comment="defconf"]
           /interface bonding remove [find comment="defconf"]
          }
          :log info Defconf_script_finished;
          :set defconfMode;
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 13149
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: Script for setting Locally Administered MAC Address on bridges

Tue Jul 16, 2024 1:23 am

2+2=5:

Good thing you have all the scripts, otherwise how would we mortals do without you telling us in advance what we need?
Praise be to you.

*************************

2+2=5 4:
And in any case it doesn't seem identical to what is actually used (from which comes the fragment I posted above).

*************************

2+2=5:
Thank goodness you're here to explain these things to me, otherwise how would I do it?

*************************

2+2=5 4:
The CRS models, OBVIOUSLY being SWITCH and not ROUTER, OBVIOUSLY the script do not creat the "WAN" and all the interfaces are in the same bridge.
Does it take so much to understand this, instead of insisting with this nonsense?

And about MGMT interface, with what is usually meant(**), MikroTik default config script do not create one.

(**) ethernet out of any bridge, not on WAN, not on LAN, dedicated only for management pourposes.

On some devices, like the ether13 on CCR2116-12G-4S+, the dedicated MGMT port exist (and is not ether1...)

anoter excerpt from defconf original code

[…]
# CloudRouterSwitches
:if ($board->"prefix"~"CloudRouterSwitch") do={

  :if ($numWlans > 0) do={
    :set configMode "ap_router";
    :set installation "indoor";
    :set wanPorts {"ether1"};
  } else={
    :set configMode "switch";
  }
}
# Special Case CCRs
:if ($board->"model"~"CCR2116") do={
  :if ($board->"numGig" = 12 && $board->"numSfpPlus" = 4) do={
    :set lanPort "ether13";
  }
}
:if ($board->"model"~"CCR2004") do={
  :if ($marketingName~"PCIe") do={
    :set configMode "switch";
  }
  :if ($board->"numGig" = 16 && $board->"numSfpPlus" = 2) do={
    :set lanPort "ether15";
  }
}
[…]
 
Apachez
Member Candidate
Member Candidate
Posts: 168
Joined: Mon Jul 01, 2024 11:45 pm

Re: Script for setting Locally Administered MAC Address on bridges

Tue Jul 16, 2024 2:19 am

You math is a bit broken or you got some other major malfunction going on...