The MAB feature can be enabled on a locked port with the command:
bridge link set dev <DEV> mab on

Signed-off-by: Hans Schultz <net...@kapio-technology.com>
---
 bridge/fdb.c                   | 17 +++++++++++++++--
 bridge/link.c                  | 21 ++++++++++++++++++---
 include/uapi/linux/if_link.h   |  1 +
 include/uapi/linux/neighbour.h |  7 ++++++-
 ip/iplink_bridge_slave.c       | 16 +++++++++++++---
 man/man8/bridge.8              | 10 ++++++++++
 man/man8/ip-link.8.in          |  8 ++++++++
 7 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/bridge/fdb.c b/bridge/fdb.c
index 5f71bde0..0fbe9bd3 100644
--- a/bridge/fdb.c
+++ b/bridge/fdb.c
@@ -93,7 +93,7 @@ static int state_a2n(unsigned int *s, const char *arg)
        return 0;
 }
 
-static void fdb_print_flags(FILE *fp, unsigned int flags)
+static void fdb_print_flags(FILE *fp, unsigned int flags, __u8 ext_flags)
 {
        open_json_array(PRINT_JSON,
                        is_json_context() ?  "flags" : "");
@@ -116,6 +116,9 @@ static void fdb_print_flags(FILE *fp, unsigned int flags)
        if (flags & NTF_STICKY)
                print_string(PRINT_ANY, NULL, "%s ", "sticky");
 
+       if (ext_flags & NTF_EXT_LOCKED)
+               print_string(PRINT_ANY, NULL, "%s ", "locked");
+
        close_json_array(PRINT_JSON, NULL);
 }
 
@@ -144,6 +147,7 @@ int print_fdb(struct nlmsghdr *n, void *arg)
        struct ndmsg *r = NLMSG_DATA(n);
        int len = n->nlmsg_len;
        struct rtattr *tb[NDA_MAX+1];
+       __u32 ext_flags = 0;
        __u16 vid = 0;
 
        if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
@@ -170,6 +174,9 @@ int print_fdb(struct nlmsghdr *n, void *arg)
        parse_rtattr(tb, NDA_MAX, NDA_RTA(r),
                     n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
 
+       if (tb[NDA_FLAGS_EXT])
+               ext_flags = rta_getattr_u32(tb[NDA_FLAGS_EXT]);
+
        if (tb[NDA_VLAN])
                vid = rta_getattr_u16(tb[NDA_VLAN]);
 
@@ -266,7 +273,7 @@ int print_fdb(struct nlmsghdr *n, void *arg)
        if (show_stats && tb[NDA_CACHEINFO])
                fdb_print_stats(fp, RTA_DATA(tb[NDA_CACHEINFO]));
 
-       fdb_print_flags(fp, r->ndm_flags);
+       fdb_print_flags(fp, r->ndm_flags, ext_flags);
 
 
        if (tb[NDA_MASTER])
@@ -414,6 +421,7 @@ static int fdb_modify(int cmd, int flags, int argc, char 
**argv)
        char *endptr;
        short vid = -1;
        __u32 nhid = 0;
+       __u32 ext_flags = 0;
 
        while (argc > 0) {
                if (strcmp(*argv, "dev") == 0) {
@@ -527,6 +535,11 @@ static int fdb_modify(int cmd, int flags, int argc, char 
**argv)
        if (dst_ok)
                addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen);
 
+       if (ext_flags &&
+           addattr_l(&req.n, sizeof(req), NDA_FLAGS_EXT, &ext_flags,
+                     sizeof(ext_flags)) < 0)
+               return -1;
+
        if (vid >= 0)
                addattr16(&req.n, sizeof(req), NDA_VLAN, vid);
        if (nhid > 0)
diff --git a/bridge/link.c b/bridge/link.c
index 3810fa04..dd69d7c3 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -181,9 +181,14 @@ static void print_protinfo(FILE *fp, struct rtattr *attr)
                if (prtb[IFLA_BRPORT_ISOLATED])
                        print_on_off(PRINT_ANY, "isolated", "isolated %s ",
                                     
rta_getattr_u8(prtb[IFLA_BRPORT_ISOLATED]));
-               if (prtb[IFLA_BRPORT_LOCKED])
-                       print_on_off(PRINT_ANY, "locked", "locked %s ",
-                                    rta_getattr_u8(prtb[IFLA_BRPORT_LOCKED]));
+               if (prtb[IFLA_BRPORT_LOCKED]) {
+                       if (prtb[IFLA_BRPORT_MAB] && 
rta_getattr_u8(prtb[IFLA_BRPORT_MAB]))
+                               print_on_off(PRINT_ANY, "locked mab", "locked 
mab %s ",
+                                            
rta_getattr_u8(prtb[IFLA_BRPORT_LOCKED]));
+                       else
+                               print_on_off(PRINT_ANY, "locked", "locked %s ",
+                                            
rta_getattr_u8(prtb[IFLA_BRPORT_LOCKED]));
+               }
        } else
                print_stp_state(rta_getattr_u8(attr));
 }
@@ -281,6 +286,7 @@ static void usage(void)
                "                               [ vlan_tunnel {on | off} ]\n"
                "                               [ isolated {on | off} ]\n"
                "                               [ locked {on | off} ]\n"
+               "                               [ mab {on | off} ]\n"
                "                               [ hwmode {vepa | veb} ]\n"
                "                               [ backup_port DEVICE ] [ 
nobackup_port ]\n"
                "                               [ self ] [ master ]\n"
@@ -312,6 +318,7 @@ static int brlink_modify(int argc, char **argv)
        __s8 bcast_flood = -1;
        __s8 mcast_to_unicast = -1;
        __s8 locked = -1;
+       __s8 macauth = -1;
        __s8 isolated = -1;
        __s8 hairpin = -1;
        __s8 bpdu_guard = -1;
@@ -437,6 +444,11 @@ static int brlink_modify(int argc, char **argv)
                        locked = parse_on_off("locked", *argv, &ret);
                        if (ret)
                                return ret;
+               } else if (strcmp(*argv, "mab") == 0) {
+                       NEXT_ARG();
+                       macauth = parse_on_off("mab", *argv, &ret);
+                       if (ret)
+                               return ret;
                } else if (strcmp(*argv, "backup_port") == 0) {
                        NEXT_ARG();
                        backup_port_idx = ll_name_to_index(*argv);
@@ -520,6 +532,9 @@ static int brlink_modify(int argc, char **argv)
        if (locked >= 0)
                addattr8(&req.n, sizeof(req), IFLA_BRPORT_LOCKED, locked);
 
+       if (macauth >= 0)
+               addattr8(&req.n, sizeof(req), IFLA_BRPORT_MAB, macauth);
+
        if (backup_port_idx != -1)
                addattr32(&req.n, sizeof(req), IFLA_BRPORT_BACKUP_PORT,
                          backup_port_idx);
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 7494cffb..58a002de 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -559,6 +559,7 @@ enum {
        IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT,
        IFLA_BRPORT_MCAST_EHT_HOSTS_CNT,
        IFLA_BRPORT_LOCKED,
+       IFLA_BRPORT_MAB,
        __IFLA_BRPORT_MAX
 };
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
index a998bf76..4dda051b 100644
--- a/include/uapi/linux/neighbour.h
+++ b/include/uapi/linux/neighbour.h
@@ -52,7 +52,8 @@ enum {
 #define NTF_STICKY     (1 << 6)
 #define NTF_ROUTER     (1 << 7)
 /* Extended flags under NDA_FLAGS_EXT: */
-#define NTF_EXT_MANAGED        (1 << 0)
+#define NTF_EXT_MANAGED                (1 << 0)
+#define NTF_EXT_LOCKED         (1 << 1)
 
 /*
  *     Neighbor Cache Entry States.
@@ -86,6 +87,10 @@ enum {
  * NTF_EXT_MANAGED flagged neigbor entries are managed by the kernel on behalf
  * of a user space control plane, and automatically refreshed so that (if
  * possible) they remain in NUD_REACHABLE state.
+ *
+ * NTF_EXT_LOCKED flagged FDB entries are placeholder entries used with the
+ * locked port feature, that ensures that an entry exists while at the same
+ * time dropping packets on ingress with src MAC and VID matching the entry.
  */
 
 struct nda_cacheinfo {
diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c
index 98d17213..0c0894eb 100644
--- a/ip/iplink_bridge_slave.c
+++ b/ip/iplink_bridge_slave.c
@@ -44,6 +44,7 @@ static void print_explain(FILE *f)
                "                       [ vlan_tunnel {on | off} ]\n"
                "                       [ isolated {on | off} ]\n"
                "                       [ locked {on | off} ]\n"
+               "                       [ mab {on | off} ]\n"
                "                       [ backup_port DEVICE ] [ nobackup_port 
]\n"
        );
 }
@@ -284,9 +285,14 @@ static void bridge_slave_print_opt(struct link_util *lu, 
FILE *f,
                print_on_off(PRINT_ANY, "isolated", "isolated %s ",
                             rta_getattr_u8(tb[IFLA_BRPORT_ISOLATED]));
 
-       if (tb[IFLA_BRPORT_LOCKED])
-               print_on_off(PRINT_ANY, "locked", "locked %s ",
-                            rta_getattr_u8(tb[IFLA_BRPORT_LOCKED]));
+       if (tb[IFLA_BRPORT_LOCKED]) {
+               if (tb[IFLA_BRPORT_MAB] && rta_getattr_u8(tb[IFLA_BRPORT_MAB]))
+                       print_on_off(PRINT_ANY, "locked mab", "locked mab %s ",
+                                    rta_getattr_u8(tb[IFLA_BRPORT_LOCKED]));
+               else
+                       print_on_off(PRINT_ANY, "locked", "locked %s ",
+                                    rta_getattr_u8(tb[IFLA_BRPORT_LOCKED]));
+       }
 
        if (tb[IFLA_BRPORT_BACKUP_PORT]) {
                int backup_p = rta_getattr_u32(tb[IFLA_BRPORT_BACKUP_PORT]);
@@ -411,6 +417,10 @@ static int bridge_slave_parse_opt(struct link_util *lu, 
int argc, char **argv,
                        NEXT_ARG();
                        bridge_slave_parse_on_off("locked", *argv, n,
                                                  IFLA_BRPORT_LOCKED);
+               } else if (matches(*argv, "mab") == 0) {
+                       NEXT_ARG();
+                       bridge_slave_parse_on_off("mab", *argv, n,
+                                                 IFLA_BRPORT_MAB);
                } else if (matches(*argv, "backup_port") == 0) {
                        int ifindex;
 
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index d4df772e..40250477 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -54,6 +54,7 @@ bridge \- show / manipulate bridge addresses and devices
 .BR vlan_tunnel " { " on " | " off " } ] [ "
 .BR isolated " { " on " | " off " } ] [ "
 .BR locked " { " on " | " off " } ] [ "
+.BR mab " { " on " | " off " } ] [ "
 .B backup_port
 .IR  DEVICE " ] ["
 .BR nobackup_port " ] [ "
@@ -580,6 +581,15 @@ The common use is that hosts are allowed access through 
authentication
 with the IEEE 802.1X protocol or based on whitelists or like setups.
 By default this flag is off.
 
+.TP
+.RB "mab on " or " mab off "
+Enables or disables the MAB/MacAuth feature. This feature can only be
+activated on a port that is in locked mode, and when enabled it extends the
+locked port feature so that MAC address can get access through a locked
+port based on acceptlists, thus it is a much simpler procedure for a
+device to become authorized than f.ex. the 802.1X protocol, and is used
+for devices that are not capable of password or crypto based authorization
+methods.
 
 .TP
 .BI backup_port " DEVICE"
diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
index fc9d62fc..187ca7ca 100644
--- a/man/man8/ip-link.8.in
+++ b/man/man8/ip-link.8.in
@@ -2454,6 +2454,9 @@ the following additional arguments are supported:
 .BR isolated " { " on " | " off " }"
 ] [
 .BR locked " { " on " | " off " }"
+] [
+.BR mab " { " on " | " off " }"
+] [
 .BR backup_port " DEVICE"
 ] [
 .BR nobackup_port " ]"
@@ -2560,6 +2563,11 @@ default this flag is off.
 behind the port cannot communicate through the port unless a FDB entry
 representing the host is in the FDB. By default this flag is off.
 
+.BR mab " { " on " | " off " }"
+- enables or disables the MAB/MacAuth feature on a locked port. It is
+thus possible for a device to gain authorization on a locked port based
+on acceptlists.
+
 .BI backup_port " DEVICE"
 - if the port loses carrier all traffic will be redirected to the
 configured backup port
-- 
2.34.1

Reply via email to