BAL and Maple Release 2.2

Signed-off-by: Shad Ansari <developer@Carbon.local>
diff --git a/bal_release/src/lib/libtopology/Makefile b/bal_release/src/lib/libtopology/Makefile
new file mode 100644
index 0000000..7507881
--- /dev/null
+++ b/bal_release/src/lib/libtopology/Makefile
@@ -0,0 +1,36 @@
+###############################################################################
+#
+#  <:copyright-BRCM:2016:DUAL/GPL:standard
+#  
+#     Copyright (c) 2016 Broadcom
+#     All Rights Reserved
+#  
+#  Unless you and Broadcom execute a separate written software license
+#  agreement governing use of this software, this software is licensed
+#  to you under the terms of the GNU General Public License version 2
+#  (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
+#  with the following added to such license:
+#  
+#     As a special exception, the copyright holders of this software give
+#     you permission to link this software with independent modules, and
+#     to copy and distribute the resulting executable under terms of your
+#     choice, provided that you also meet, for each linked independent
+#     module, the terms and conditions of the license of that module.
+#     An independent module is a module which is not derived from this
+#     software.  The special exception does not apply to any modifications
+#     of the software.
+#  
+#  Not withstanding the above, under no circumstances may you combine
+#  this software in any way with any other Broadcom software provided
+#  under a license other than the GPL, without Broadcom's express prior
+#  written consent.
+#  
+#  :>
+#
+###############################################################################
+MOD_NAME = topology
+MOD_TYPE = lib
+MOD_DEPS = dev_log maple_sdk
+
+srcs = bcm_topo.c
+
diff --git a/bal_release/src/lib/libtopology/bcm_topo.c b/bal_release/src/lib/libtopology/bcm_topo.c
new file mode 100644
index 0000000..4b092a0
--- /dev/null
+++ b/bal_release/src/lib/libtopology/bcm_topo.c
@@ -0,0 +1,650 @@
+/******************************************************************************
+ *
+ *  <:copyright-BRCM:2016:DUAL/GPL:standard
+ *
+ *     Copyright (c) 2016 Broadcom
+ *     All Rights Reserved
+ *
+ *  Unless you and Broadcom execute a separate written software license
+ *  agreement governing use of this software, this software is licensed
+ *  to you under the terms of the GNU General Public License version 2
+ *  (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
+ *  with the following added to such license:
+ *
+ *     As a special exception, the copyright holders of this software give
+ *     you permission to link this software with independent modules, and
+ *     to copy and distribute the resulting executable under terms of your
+ *     choice, provided that you also meet, for each linked independent
+ *     module, the terms and conditions of the license of that module.
+ *     An independent module is a module which is not derived from this
+ *     software.  The special exception does not apply to any modifications
+ *     of the software.
+ *
+ *  Not withstanding the above, under no circumstances may you combine
+ *  this software in any way with any other Broadcom software provided
+ *  under a license other than the GPL, without Broadcom's express prior
+ *  written consent.
+ *
+ *  :>
+ *
+ *****************************************************************************/
+
+#include <bcm_dev_log.h>
+#include <bcmolt_math.h>
+#include "bcm_topo.h"
+
+#define BCM_TOPO_MAX_LINE_SIZE 256
+#define BCM_TOPO_MAX_NNI_DEVICES 1
+
+uint32_t g_max_nni_ports[BCM_TOPO_MAX_NNI_DEVICES] = {BCM_TOPO_MAX_NNI_PORTS};
+
+typedef struct bcm_topo_dev_context_t bcm_topo_dev_context_t;
+
+typedef struct
+{
+    bcm_topo_dev_context_t *dev; /* Back pointer to the physical device this PON belongs to */
+    bcmos_bool is_initialized;
+    uint32_t pon_id;
+    uint32_t logical_pon;
+    bcm_topo_pon_mode pon_mode;
+    uint32_t max_num_of_onus;
+    void *contexts[BCM_TOPO_PON_CONTEXT_ID__NUM_OF]; /* User context - 1 entry per user */
+} bcm_topo_pon_context_t;
+
+struct bcm_topo_dev_context_t
+{
+    bcm_topo_pon_mode pon_mode; /* Currently we do not allow more than one PON mode per device (e.g: GPONx8 + XGPONx4) */
+    bcmos_bool is_initialized;
+    uint32_t device_id;
+    uint32_t max_num_of_pons;
+    bcm_topo_pon_context_t pons[BCM_TOPO_MAX_NUM_OF_PONS_PER_DEV];
+};
+
+typedef struct
+{
+    bcmos_bool is_initialized;
+    bcm_topo_dev_context_t devs[BCM_TOPO_MAX_NUM_OF_DEVS];
+    bcm_topo_pon_context_t *logical_pon2physical_pon[BCM_TOPO_MAX_NUM_OF_LOGICAL_PONS];
+} bcm_topo_context_t;
+
+static bcm_topo_context_t bcm_topo_context;
+
+#ifdef ENABLE_LOG
+static dev_log_id topo_log_id = DEV_LOG_INVALID_ID;
+#endif
+
+static int2str_t pon_mode2str[] =
+{
+    {BCM_TOPO_PON_MODE_GPON, "gpon"},
+    {BCM_TOPO_PON_MODE_XGPON, "xgpon"},
+    {BCM_TOPO_PON_MODE_XGS, "xgs"},
+    {BCM_TOPO_PON_MODE_EPON_TDMA, "epon_tdma"},
+    {BCM_TOPO_PON_MODE_EPON_1G, "epon_1g"},
+    {BCM_TOPO_PON_MODE_EPON_10G, "epon_10g"},
+    {-1},
+};
+
+static int2int_t pon_mode2max_num_of_pons[] =
+{
+    {BCM_TOPO_PON_MODE_GPON, 16},
+    {BCM_TOPO_PON_MODE_XGPON, 8},
+    {BCM_TOPO_PON_MODE_XGS, 2},
+    {BCM_TOPO_PON_MODE_EPON_TDMA, 8},
+    {BCM_TOPO_PON_MODE_EPON_1G, 16},
+    {BCM_TOPO_PON_MODE_EPON_10G, 8},
+    {-1},
+};
+
+const char *bcm_topo_dev_get_pon_mode_str(bcmolt_devid device_id)
+{
+    return int2str(pon_mode2str, bcm_topo_context.devs[device_id].pon_mode);
+}
+
+int bcm_topo_dev_get_max_pon(bcmolt_devid device_id)
+{
+    return int2int(pon_mode2max_num_of_pons, bcm_topo_context.devs[device_id].pon_mode);
+}
+
+bcm_topo_pon_mode bcm_topo_pon_get_pon_mode(uint32_t pon)
+{
+    bcmolt_devid device_id;
+    uint32_t physical_pon;
+    bcmos_errno rc;
+
+    rc = bcm_topo_pon_get_logical2physical(pon, &device_id, &physical_pon);
+    if (rc != BCM_ERR_OK)
+        return BCM_TOPO_PON_MODE_INVALID;
+
+    return bcm_topo_context.devs[device_id].pons[physical_pon].pon_mode;
+}
+
+bcm_topo_pon_family bcm_topo_pon_get_pon_family(uint32_t pon)
+{
+    switch (bcm_topo_pon_get_pon_mode(pon))
+    {
+    case BCM_TOPO_PON_MODE_GPON:
+    case BCM_TOPO_PON_MODE_XGPON:
+    case BCM_TOPO_PON_MODE_XGS:
+        return BCM_TOPO_PON_FAMILY_GPON;
+    case BCM_TOPO_PON_MODE_EPON_TDMA:
+    case BCM_TOPO_PON_MODE_EPON_1G:
+    case BCM_TOPO_PON_MODE_EPON_10G:
+        return BCM_TOPO_PON_FAMILY_EPON;
+    default:
+        return BCM_TOPO_PON_FAMILY_INVALID;
+    }
+}
+
+bcm_topo_pon_sub_family bcm_topo_pon_get_pon_sub_family(uint32_t pon)
+{
+    switch (bcm_topo_pon_get_pon_mode(pon))
+    {
+    case BCM_TOPO_PON_MODE_GPON:
+        return BCM_TOPO_PON_SUB_FAMILY_GPON;
+    case BCM_TOPO_PON_MODE_XGPON:
+    case BCM_TOPO_PON_MODE_XGS:
+        return BCM_TOPO_PON_SUB_FAMILY_XGPON;
+    case BCM_TOPO_PON_MODE_EPON_TDMA:
+    case BCM_TOPO_PON_MODE_EPON_1G:
+    case BCM_TOPO_PON_MODE_EPON_10G:
+        return BCM_TOPO_PON_SUB_FAMILY_EPON;
+    default:
+        return BCM_TOPO_PON_SUB_FAMILY_INVALID;
+    }
+}
+
+uint32_t bcm_topo_pon_get_max_num_of_onus(uint32_t pon)
+{
+    bcmolt_devid device_id;
+    uint32_t physical_pon;
+    bcmos_errno rc;
+
+    rc = bcm_topo_pon_get_logical2physical(pon, &device_id, &physical_pon);
+    if (rc != BCM_ERR_OK)
+        return BCM_TOPO_ERR_INVALID;
+
+    return bcm_topo_context.devs[device_id].pons[physical_pon].max_num_of_onus;
+}
+
+bcmos_bool bcm_topo_pon_is_valid(uint32_t pon)
+{
+    bcmolt_devid device_id;
+    uint32_t physical_pon;
+
+    if (bcm_topo_pon_get_logical2physical(pon, &device_id, &physical_pon) != BCM_ERR_OK)
+        return BCMOS_FALSE;
+
+    return BCMOS_TRUE;
+}
+
+bcmolt_devid bcm_topo_dev_get_next(bcmolt_devid device_id)
+{
+    if (device_id == BCM_TOPO_DEV_INVALID)
+        device_id = 0;
+    else
+        device_id++;
+
+    for (; device_id < BCM_TOPO_MAX_NUM_OF_DEVS && !bcm_topo_context.devs[device_id].is_initialized; device_id++);
+
+    return device_id == BCM_TOPO_MAX_NUM_OF_DEVS ? BCM_TOPO_DEV_INVALID : device_id;
+}
+
+uint32_t bcm_topo_pon_get_next(bcmolt_devid device_id, uint32_t pon)
+{
+    uint32_t physical_pon;
+    bcmos_errno rc;
+
+    if (device_id >= BCM_TOPO_MAX_NUM_OF_DEVS)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Device ID must be in the range 0 .. %u\n", BCM_TOPO_MAX_NUM_OF_DEVS - 1);
+        return BCM_TOPO_PON_INVALID;
+    }
+
+    if (pon == BCM_TOPO_PON_INVALID)
+        physical_pon = 0;
+    else
+    {
+        bcmolt_devid dummy;
+
+        rc = bcm_topo_pon_get_logical2physical(pon, &dummy, &physical_pon);
+        if (rc != BCM_ERR_OK)
+        {
+            return BCM_TOPO_PON_INVALID;
+        }
+        else
+        {
+            physical_pon++;
+        }
+    }
+
+    if (physical_pon < bcm_topo_context.devs[device_id].max_num_of_pons)
+    {
+        rc = bcm_topo_pon_get_physical2logical(device_id, physical_pon, &pon);
+        if (rc != BCM_ERR_OK)
+        {
+            return BCM_TOPO_PON_INVALID;
+        }
+        else
+        {
+            return pon;
+        }
+    }
+
+    return BCM_TOPO_PON_INVALID;
+}
+
+bcmos_errno bcm_topo_pon_get_logical2physical(uint32_t logical_pon, bcmolt_devid *device_id, uint32_t *physical_pon)
+{
+    if (logical_pon >= BCM_TOPO_MAX_NUM_OF_LOGICAL_PONS)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Logical PON ID must be in the range 0 .. %u\n", BCM_TOPO_MAX_NUM_OF_LOGICAL_PONS - 1);
+        return BCM_ERR_RANGE;
+    }
+
+    if (!bcm_topo_context.logical_pon2physical_pon[logical_pon])
+    {
+        BCM_LOG(ERROR, topo_log_id, "Logical PON=%u was not associated with a physical PON\n", logical_pon);
+        return BCM_ERR_RANGE;
+    }
+
+    *physical_pon = bcm_topo_context.logical_pon2physical_pon[logical_pon]->pon_id;
+    *device_id = bcm_topo_context.logical_pon2physical_pon[logical_pon]->dev->device_id;
+
+    return BCM_ERR_OK;
+}
+
+bcmos_errno bcm_topo_pon_get_physical2logical(bcmolt_devid device_id, uint32_t physical_pon, uint32_t *logical_pon)
+{
+    if (device_id >= BCM_TOPO_MAX_NUM_OF_DEVS)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Device ID must be in the range 0 .. %u\n", BCM_TOPO_MAX_NUM_OF_DEVS - 1);
+        return BCM_ERR_RANGE;
+    }
+
+    if (physical_pon >= bcm_topo_context.devs[device_id].max_num_of_pons)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Physical PON ID must be in the range 0 .. %u\n", bcm_topo_context.devs[device_id].max_num_of_pons - 1);
+        return BCM_ERR_RANGE;
+    }
+
+    if (bcm_topo_context.devs[device_id].pons[physical_pon].logical_pon == BCM_TOPO_PON_INVALID)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Physical PON=%u on device=%u was not associated with a logical PON\n", physical_pon, device_id);
+        return BCM_ERR_RANGE;
+    }
+
+    *logical_pon = bcm_topo_context.devs[device_id].pons[physical_pon].logical_pon;
+
+    return BCM_ERR_OK;
+}
+
+bcmos_errno bcm_topo_pon_set_context(uint32_t pon, bcm_topo_pon_context_id pon_context_id, void *context)
+{
+    bcmolt_devid device_id;
+    uint32_t physical_pon;
+    bcmos_errno rc;
+
+    if (pon_context_id >= BCM_TOPO_PON_CONTEXT_ID__NUM_OF)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Invalid PON context ID\n");
+        return BCM_ERR_RANGE;
+    }
+
+    rc = bcm_topo_pon_get_logical2physical(pon, &device_id, &physical_pon);
+    if (rc != BCM_ERR_OK)
+        return rc;
+
+    bcm_topo_context.devs[device_id].pons[physical_pon].contexts[pon_context_id] = context;
+
+    return BCM_ERR_OK;
+}
+
+void *bcm_topo_pon_get_context(uint32_t pon, bcm_topo_pon_context_id pon_context_id)
+{
+    bcmolt_devid device_id;
+    uint32_t physical_pon;
+    bcmos_errno rc;
+
+    if (pon_context_id >= BCM_TOPO_PON_CONTEXT_ID__NUM_OF)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Invalid PON context ID\n");
+        return NULL;
+    }
+
+    rc = bcm_topo_pon_get_logical2physical(pon, &device_id, &physical_pon);
+    if (rc != BCM_ERR_OK)
+        return NULL;
+
+    return bcm_topo_context.devs[device_id].pons[physical_pon].contexts[pon_context_id];
+}
+
+static void bcm_topo_init_context(void)
+{
+    uint32_t device_id;
+
+    for (device_id = 0; device_id < BCM_TOPO_MAX_NUM_OF_DEVS; device_id++)
+    {
+        bcm_topo_dev_context_t *dev;
+        uint32_t pon_id;
+
+        dev = &bcm_topo_context.devs[device_id];
+        dev->device_id = device_id;
+        dev->pon_mode = BCM_TOPO_PON_MODE_INVALID;
+        for (pon_id = 0; pon_id < BCM_TOPO_MAX_NUM_OF_PONS_PER_DEV; pon_id++)
+        {
+            bcm_topo_pon_context_t *pon;
+
+            pon = &dev->pons[pon_id];
+            pon->dev = dev;
+            pon->pon_id = pon_id;
+            pon->pon_mode = BCM_TOPO_PON_MODE_INVALID;
+            pon->logical_pon = BCM_TOPO_PON_INVALID;
+        }
+    }
+}
+
+static bcmos_errno bcm_topo_init_line_parse(const char *line, const char *filename, uint32_t line_num, bcmos_bool *is_skipped, uint32_t *logical_pon, bcm_topo_pon_mode *pon_mode,
+    uint32_t *device_id, uint32_t *physical_pon)
+{
+    int rc;
+    char logical_pon_str[BCM_TOPO_MAX_LINE_SIZE];
+    char pon_mode_str[BCM_TOPO_MAX_LINE_SIZE];
+    char device_id_str[BCM_TOPO_MAX_LINE_SIZE];
+    char physical_pon_str[BCM_TOPO_MAX_LINE_SIZE];
+    int2str_t *p;
+
+    /* Skip blank lines and comments. */
+    if (!*line || *line == '\n' || *line == '#')
+    {
+        *is_skipped = BCMOS_TRUE;
+        return BCM_ERR_OK;
+    }
+
+    *is_skipped = BCMOS_FALSE;
+
+    /* Read the tokens separated by commas. */
+    rc = sscanf(line, "%[^,],%*[ ]%[^,],%[^,],%[^\n]", logical_pon_str, pon_mode_str, device_id_str, physical_pon_str);
+    if (rc < 4)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Error parsing line %s:%u (rc=%u)\n", filename, line_num, rc);
+        return BCM_ERR_PARSE;
+    }
+
+    if (sscanf(logical_pon_str, "%u", logical_pon) < 1)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Error parsing line %s:%u (rc=%u)\n", filename, line_num, rc);
+        return BCM_ERR_PARSE;
+    }
+
+    if (sscanf(device_id_str, "%u", device_id) < 1)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Error parsing line %s:%u (rc=%u)\n", filename, line_num, rc);
+        return BCM_ERR_PARSE;
+    }
+
+    if (sscanf(physical_pon_str, "%u", physical_pon) < 1)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Error parsing line %s:%u (rc=%u)\n", filename, line_num, rc);
+        return BCM_ERR_PARSE;
+    }
+
+    BCM_LOG(INFO, topo_log_id, "Map Logical PON ID=%u -> (Physical Device ID=%u, Physical Pon ID=%u, PON mode='%s')\n", *logical_pon, *device_id, *physical_pon, pon_mode_str);
+
+    for (p = pon_mode2str; p->from != -1 && strcmp(pon_mode_str, p->to); p++);
+
+    if (p->from == -1)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Error parsing PON mode at %s:%u\n", filename, line_num);
+        return BCM_ERR_PARSE;
+    }
+
+    *pon_mode = p->from;
+
+    return BCM_ERR_OK;
+}
+
+static void bcm_topo_init_dev(bcm_topo_dev_context_t *dev, bcm_topo_pon_mode pon_mode)
+{
+    dev->pon_mode = pon_mode;
+    dev->max_num_of_pons = int2int(pon_mode2max_num_of_pons, pon_mode);
+}
+
+static void bcm_topo_init_pon(bcm_topo_pon_context_t *pon, bcm_topo_pon_mode pon_mode)
+{
+    pon->pon_mode = pon_mode;
+    switch (pon_mode)
+    {
+    case BCM_TOPO_PON_MODE_GPON:
+        pon->max_num_of_onus = 128;
+        break;
+    case BCM_TOPO_PON_MODE_XGPON:
+    case BCM_TOPO_PON_MODE_XGS:
+        pon->max_num_of_onus = 256;
+        break;
+    case BCM_TOPO_PON_MODE_EPON_TDMA:
+    case BCM_TOPO_PON_MODE_EPON_1G:
+    case BCM_TOPO_PON_MODE_EPON_10G:
+        pon->max_num_of_onus = 0; /* There is no "ONU" in EPON, but LLIDs. */
+        break;
+    default:
+        break;
+    }
+}
+
+static bcmos_errno bcm_topo_init_by_file(FILE *fp, const char *filename)
+{
+    char line[BCM_TOPO_MAX_LINE_SIZE];
+    uint32_t line_num;
+
+    /* Read next line. */
+    line_num = 1;
+    while (fgets(line, sizeof(line), fp))
+    {
+        bcmos_bool is_skipped;
+        uint32_t logical_pon, device_id, physical_pon;
+        bcm_topo_pon_mode pon_mode;
+        bcm_topo_dev_context_t *dev;
+        bcm_topo_pon_context_t *pon;
+
+        if (bcm_topo_init_line_parse(line, filename, line_num, &is_skipped, &logical_pon, &pon_mode, &device_id, &physical_pon) != BCM_ERR_OK)
+            return BCM_ERR_PARSE;
+
+        if (is_skipped)
+        {
+            line_num++;
+            continue;
+        }
+
+        if (logical_pon >= BCM_TOPO_MAX_NUM_OF_LOGICAL_PONS)
+        {
+            BCM_LOG(ERROR, topo_log_id, "Logical PON ID at %s:%u must be in the range 0 .. %u\n", filename, line_num, BCM_TOPO_MAX_NUM_OF_LOGICAL_PONS - 1);
+            return BCM_ERR_RANGE;
+        }
+
+        if (bcm_topo_context.logical_pon2physical_pon[logical_pon])
+        {
+            BCM_LOG(ERROR, topo_log_id, "Logical PON ID at %s:%u has already been set before\n", filename, line_num);
+            return BCM_ERR_ALREADY;
+        }
+
+        if (device_id >= BCM_TOPO_MAX_NUM_OF_DEVS)
+        {
+            BCM_LOG(ERROR, topo_log_id, "Physical device ID at %s:%u must be in the range 0 .. %u\n", filename, line_num, BCM_TOPO_MAX_NUM_OF_DEVS - 1);
+            return BCM_ERR_RANGE;
+        }
+
+        dev = &bcm_topo_context.devs[device_id];
+        if (!dev->is_initialized)
+        {
+            bcm_topo_init_dev(dev, pon_mode);
+            dev->is_initialized = BCMOS_TRUE;
+        }
+        else if (dev->pon_mode != pon_mode)
+        {
+            BCM_LOG(ERROR, topo_log_id, "PON mode at %s:%u conflicts with PON mode='%s' that has already been set for this device\n", filename, line_num,
+                int2str(pon_mode2str, dev->pon_mode));
+            return BCM_ERR_NOT_SUPPORTED;
+        }
+
+        if (physical_pon >= dev->max_num_of_pons)
+        {
+            BCM_LOG(ERROR, topo_log_id, "Physical PON ID at %s:%u must be in the range 0 .. %u\n", filename, line_num, dev->max_num_of_pons - 1);
+            return BCM_ERR_RANGE;
+        }
+
+        pon = &bcm_topo_context.devs[device_id].pons[physical_pon];
+        if (!pon->is_initialized)
+        {
+            bcm_topo_init_pon(pon, pon_mode);
+            pon->is_initialized = BCMOS_TRUE;
+        }
+        else
+        {
+            BCM_LOG(ERROR, topo_log_id, "Physical PON ID at %s:%u has already been set before\n", filename, line_num);
+            return BCM_ERR_ALREADY;
+        }
+
+        bcm_topo_context.logical_pon2physical_pon[logical_pon] = &bcm_topo_context.devs[device_id].pons[physical_pon];
+        bcm_topo_context.devs[device_id].pons[physical_pon].logical_pon = logical_pon;
+
+        line_num++;
+    }
+
+    return BCM_ERR_OK;
+}
+
+static bcmos_errno bcm_topo_init_by_args(bcm_topo_params *params)
+{
+    uint32_t device_id;
+    uint32_t max_num_of_pons_per_dev;
+
+    if (params->num_of_devs > BCM_TOPO_MAX_NUM_OF_DEVS)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Number of devices must be in the range 0 .. %u\n", BCM_TOPO_MAX_NUM_OF_DEVS);
+        return BCM_ERR_RANGE;
+    }
+
+    max_num_of_pons_per_dev = int2int(pon_mode2max_num_of_pons, params->pon_mode);
+
+    if (params->num_of_pons_per_dev > max_num_of_pons_per_dev)
+    {
+        BCM_LOG(ERROR, topo_log_id, "Number of PONs per device for PON mode '%s' must be in the range 0 .. %u\n", int2str(pon_mode2str, params->pon_mode), BCM_TOPO_MAX_NUM_OF_DEVS);
+        return BCM_ERR_RANGE;
+    }
+
+    for (device_id = 0; device_id < params->num_of_devs; device_id++)
+    {
+        uint32_t physical_pon;
+        bcm_topo_dev_context_t *dev;
+        bcm_topo_pon_context_t *pon;
+
+        dev = &bcm_topo_context.devs[device_id];
+        bcm_topo_init_dev(dev, params->pon_mode);
+        dev->is_initialized = BCMOS_TRUE;
+
+        for (physical_pon = 0; physical_pon < params->num_of_pons_per_dev; physical_pon++)
+        {
+            uint32_t logical_pon;
+
+            logical_pon = (device_id * params->num_of_pons_per_dev) + physical_pon;
+
+            BCM_LOG(INFO, topo_log_id, "Map Logical PON ID=%u -> (Physical Device ID=%u, Physical pon ID=%u, PON mode='%s')\n", logical_pon, device_id, physical_pon,
+                int2str(pon_mode2str, params->pon_mode));
+
+            pon = &bcm_topo_context.devs[device_id].pons[physical_pon];
+            bcm_topo_init_pon(pon, params->pon_mode);
+            pon->is_initialized = BCMOS_TRUE;
+
+            bcm_topo_context.logical_pon2physical_pon[logical_pon] = &bcm_topo_context.devs[device_id].pons[physical_pon];
+            bcm_topo_context.devs[device_id].pons[physical_pon].logical_pon = logical_pon;
+        }
+    }
+
+    return BCM_ERR_OK;
+}
+
+bcmos_errno bcm_topo_init(bcm_topo_params *params, const char *topo_filename)
+{
+    bcmos_errno ret;
+    FILE *topo_fp;
+
+#ifdef ENABLE_LOG
+    if (topo_log_id == DEV_LOG_INVALID_ID)
+    {
+        topo_log_id = bcm_dev_log_id_register("TOPOLOGY", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
+        BUG_ON(topo_log_id == DEV_LOG_INVALID_ID);
+    }
+#endif
+
+    bcm_topo_init_context();
+
+    topo_fp = fopen(topo_filename, "r");
+    if (topo_fp)
+    {
+        BCM_LOG(INFO, topo_log_id, "Topology is taken from file\n");
+        ret = bcm_topo_init_by_file(topo_fp, topo_filename);
+        fclose(topo_fp);
+    }
+    else if (params)
+    {
+        BCM_LOG(INFO, topo_log_id, "Topology is taken from arguments\n");
+        ret = bcm_topo_init_by_args(params);
+    }
+    else
+    {
+        BCM_LOG(INFO, topo_log_id, "At least one of topo_fp and params must be specified and exist\n");
+        ret = BCM_ERR_PARM;
+    }
+
+    if (ret != BCM_ERR_OK)
+        goto exit;
+
+    bcm_topo_context.is_initialized = BCMOS_TRUE;
+
+    ret = BCM_ERR_OK;
+
+exit:
+    return ret;
+}
+
+bcmos_bool bcm_topo_is_initialized(void)
+{
+    return bcm_topo_context.is_initialized;
+}
+
+bcmos_bool bcm_topo_dev_set_max_nni(bcmolt_devid device_id, uint32_t num_nni_ports)
+{
+    if(device_id >= BCM_TOPO_MAX_NNI_DEVICES)
+    {
+        return BCM_ERR_PARM;
+    }
+    /* make sure the max number does not exceed the allocated resrouce */
+    if( num_nni_ports > BCM_TOPO_MAX_NNI_PORTS)
+    {
+        return BCM_ERR_PARM;
+    } 
+    g_max_nni_ports[device_id] = num_nni_ports;
+
+    return BCMOS_TRUE;
+}
+
+bcmos_bool bcm_topo_dev_get_max_nni(bcmolt_devid device_id, uint32_t *p_num_nni_ports)
+{
+    if(device_id >= BCM_TOPO_MAX_NNI_DEVICES)
+    {
+        return BCM_ERR_PARM;
+    }
+     *p_num_nni_ports = g_max_nni_ports[device_id];
+
+    return BCMOS_TRUE;
+}
+
+bcmos_bool bcm_topo_nni_is_valid(uint32_t nni)
+{
+
+    if (nni >= g_max_nni_ports[0])
+        return BCMOS_FALSE;
+
+    return BCMOS_TRUE;
+}
+
diff --git a/bal_release/src/lib/libtopology/bcm_topo.h b/bal_release/src/lib/libtopology/bcm_topo.h
new file mode 100644
index 0000000..9c6ec1c
--- /dev/null
+++ b/bal_release/src/lib/libtopology/bcm_topo.h
@@ -0,0 +1,270 @@
+/******************************************************************************
+ *
+ *  <:copyright-BRCM:2016:DUAL/GPL:standard
+ *
+ *     Copyright (c) 2016 Broadcom
+ *     All Rights Reserved
+ *
+ *  Unless you and Broadcom execute a separate written software license
+ *  agreement governing use of this software, this software is licensed
+ *  to you under the terms of the GNU General Public License version 2
+ *  (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
+ *  with the following added to such license:
+ *
+ *     As a special exception, the copyright holders of this software give
+ *     you permission to link this software with independent modules, and
+ *     to copy and distribute the resulting executable under terms of your
+ *     choice, provided that you also meet, for each linked independent
+ *     module, the terms and conditions of the license of that module.
+ *     An independent module is a module which is not derived from this
+ *     software.  The special exception does not apply to any modifications
+ *     of the software.
+ *
+ *  Not withstanding the above, under no circumstances may you combine
+ *  this software in any way with any other Broadcom software provided
+ *  under a license other than the GPL, without Broadcom's express prior
+ *  written consent.
+ *
+ *  :>
+ *
+ *****************************************************************************/
+
+#ifndef _BCM_TOPO_H_
+#define _BCM_TOPO_H_
+
+#include <bcmolt_conv.h>
+#include <bcmos_system.h>
+#include <bcmolt_model_types.h>
+#include <bal_model_types.h>
+
+#define BCM_TOPO_DEV_INVALID UINT8_MAX
+#define BCM_TOPO_PON_INVALID UINT32_MAX
+#define BCM_TOPO_ERR_INVALID UINT32_MAX
+#define BCM_TOPO_MAX_NUM_OF_DEVS 8 /* Maxmimum of 8 devices per vOLT. */
+#define BCM_TOPO_MAX_NUM_OF_PONS_PER_DEV 16
+#define BCM_TOPO_MAX_NUM_OF_LOGICAL_PONS (BCM_TOPO_MAX_NUM_OF_DEVS * BCM_TOPO_MAX_NUM_OF_PONS_PER_DEV)
+
+#define BCM_TOPO_FOR_EACH_DEV(device_id) \
+    for (device_id = bcm_topo_dev_get_next(BCM_TOPO_DEV_INVALID); device_id != BCM_TOPO_DEV_INVALID; device_id = bcm_topo_dev_get_next(device_id))
+
+#define BCM_TOPO_DEV_FOR_EACH_PON(device_id, pon) \
+    for (pon = bcm_topo_pon_get_next(device_id, BCM_TOPO_PON_INVALID); pon != BCM_TOPO_PON_INVALID; pon = bcm_topo_pon_get_next(device_id, pon))
+
+#define BCM_TOPO_FOR_EACH_PON(device_id, pon) \
+    for (device_id = bcm_topo_dev_get_next(BCM_TOPO_DEV_INVALID); device_id != BCM_TOPO_DEV_INVALID; device_id = bcm_topo_dev_get_next(device_id)) \
+        BCM_TOPO_DEV_FOR_EACH_PON(device_id, pon)
+
+#define BCM_TOPO_FOR_EACH_ONU(pon, onu) \
+    for (onu = 0; onu < bcm_topo_pon_get_max_num_of_onus(pon); onu++)
+
+typedef enum
+{
+    BCM_TOPO_PON_MODE_GPON,
+    BCM_TOPO_PON_MODE_XGPON,
+    BCM_TOPO_PON_MODE_XGS,
+    BCM_TOPO_PON_MODE_EPON_TDMA,
+    BCM_TOPO_PON_MODE_EPON_1G,
+    BCM_TOPO_PON_MODE_EPON_10G,
+    BCM_TOPO_PON_MODE_INVALID,
+    BCM_TOPO_PON_MODE__NUM_OF,
+} bcm_topo_pon_mode;
+
+typedef enum
+{
+    BCM_TOPO_PON_FAMILY_GPON, /* GPON, XGPON, XGS, NGPON2 */
+    BCM_TOPO_PON_FAMILY_EPON,
+    BCM_TOPO_PON_FAMILY_INVALID,
+    BCM_TOPO_PON_FAMILY__NUM_OF,
+} bcm_topo_pon_family;
+
+typedef enum
+{
+    BCM_TOPO_PON_SUB_FAMILY_GPON, /* GPON only */
+    BCM_TOPO_PON_SUB_FAMILY_XGPON, /* XGPON, XGS, NGPON2 */
+    BCM_TOPO_PON_SUB_FAMILY_EPON,
+    BCM_TOPO_PON_SUB_FAMILY_INVALID,
+    BCM_TOPO_PON_SUB_FAMILY__NUM_OF,
+} bcm_topo_pon_sub_family;
+
+/* User context identifier - can be extended if more modules in the system use the bcm_topo.context. */
+typedef enum
+{
+    BCM_TOPO_PON_CONTEXT_ID_MAC_UTIL,
+    BCM_TOPO_PON_CONTEXT_ID_OMCI_SVC,
+    BCM_TOPO_PON_CONTEXT_ID_RSC_MGR,
+    BCM_TOPO_PON_CONTEXT_ID__NUM_OF,
+} bcm_topo_pon_context_id;
+
+typedef struct
+{
+    uint32_t num_of_devs;
+    uint32_t num_of_pons_per_dev;
+    bcm_topo_pon_mode pon_mode;
+} bcm_topo_params;
+
+/**
+ * @brief Get the PON mode of a given device ID.
+ * @param device_id            device ID
+ *
+ * @returns PON mode or Null on error
+ */
+const char *bcm_topo_dev_get_pon_mode_str(bcmolt_devid device_id);
+
+
+/**
+ * @brief Get the max number of pons of a given device ID.
+ * @param device_id            device ID
+ *
+ * @returns the max number of pons or -1 on error
+ */
+int bcm_topo_dev_get_max_pon(bcmolt_devid device_id);
+
+/**
+ * @brief Get the PON mode of a given logical PON ID.
+ * @param pon                 Logical PON ID
+ *
+ * @returns PON mode or BCM_TOPO_PON_MODE_INVALID on error
+ */
+bcm_topo_pon_mode bcm_topo_pon_get_pon_mode(uint32_t pon);
+
+/**
+ * @brief Get the PON family of a given logical PON ID.
+ * @param pon                 Logical PON ID
+ *
+ * @returns PON mode or BCM_TOPO_PON_FAMILY_INVALID on error
+ */
+bcm_topo_pon_family bcm_topo_pon_get_pon_family(uint32_t pon);
+
+/**
+ * @brief Get the PON sub-family of a given logical PON ID.
+ * @param pon                 Logical PON ID
+ *
+ * @returns PON mode or BCM_TOPO_PON_SUB_FAMILY_INVALID on error
+ */
+bcm_topo_pon_sub_family bcm_topo_pon_get_pon_sub_family(uint32_t pon);
+
+/**
+ * @brief Get the number of ONUs of a given logical PON ID.
+ * @param pon                 Logical PON ID
+ *
+ * @returns Number of ONUs or BCM_TOPO_ERR_INVALID on error
+ */
+uint32_t bcm_topo_pon_get_max_num_of_onus(uint32_t pon);
+
+/**
+ * @brief Return whether a given logical PON is in the valid range.
+ *
+ * @returns BCMOS_TRUE is the given logical PON is in the valid range, BCMOS_FALSE otherwise
+ */
+bcmos_bool bcm_topo_pon_is_valid(uint32_t pon);
+
+/**
+ * @brief Traverse devices
+ * @param device_id         Device iterator. Should be BCM_TOPO_DEV_INVALID at the beginning.
+ *
+ * @returns Next device, or BCM_TOPO_DEV_INVALID to mark that no more devices are available.
+ */
+bcmolt_devid bcm_topo_dev_get_next(bcmolt_devid device_id);
+
+/**
+ * @brief Traverse logical PONs within a given device.
+ * @param device_id         Device id
+ * @param pon               Logical PON iterator. Should be BCM_TOPO_PON_INVALID at the beginning.
+ *
+ * @returns Next logical PON on this device, or BCM_TOPO_PON_INVALID to mark that no more PONs are available.
+ */
+uint32_t bcm_topo_pon_get_next(bcmolt_devid device_id, uint32_t pon);
+
+/**
+ * @brief Get device ID and physical PON ID from logical PON ID.
+ * @param logical_pon            logical PON ID
+ * @param *device_id         Pointer to device id
+ * @param *physical_pon           Pointer to physical PON ID
+ *
+ * @returns bcmos_errno
+ * @note In general, the physical PON ID is used in the hardware directed function calls.
+ */
+bcmos_errno bcm_topo_pon_get_logical2physical(uint32_t logical_pon, bcmolt_devid *device_id, uint32_t *physical_pon);
+
+/**
+ * @brief Get logical PON ID from device ID and physical PON ID.
+ * @param device_id           Device id
+ * @param physical_pon             Physical PON ID
+ * @param *logical_pon            Pointer to logical PON ID
+ *
+ * @returns bcmos_errno
+ * @note In general, the logical PON ID is used in the BAL core directed function calls.
+ */
+bcmos_errno bcm_topo_pon_get_physical2logical(bcmolt_devid device_id, uint32_t physical_pon, uint32_t *logical_pon);
+
+/**
+ * @brief Set user context for a given logical PON ID.
+ * @param pon                 Logical PON ID
+ * @param pon_context_id      The identity of the module using the context
+ * @param context             Pointer to user context
+ *
+ * @returns bcmos_errno
+ */
+bcmos_errno bcm_topo_pon_set_context(uint32_t pon, bcm_topo_pon_context_id pon_context_id, void *context);
+
+/**
+ * @brief Get user context for a given logical PON ID.
+ * @param pon                 Logical PON ID
+ * @param pon_context_id      The identity of the module using the context
+ *
+ * @returns User context or NULL if there's an error
+ */
+void *bcm_topo_pon_get_context(uint32_t pon, bcm_topo_pon_context_id pon_context_id);
+
+/**
+ * @brief Initialize topology module, either by arguments (probably received from CLI) or by a topology file. The rule is at least one of them must be specified and exist. If both are
+ *        specified and exist, then we rely on topology file.
+ *        Pay attention that when not using a file, the user have less freedom. For example:
+ *        - The user won't be able to have devices with different PON modes.
+ *        - The user won't be able to have devices with different number of PONs.
+ *        - The user won't be able to map logical PON to (device, physical PON). We assume that logical_pon = (device * num_of_pons_per_dev) + physical_pon.
+ * @param params              Topology parameters. If NULL, we rely on topology file.
+ * @param topo_filename       File containing bcm_topo.configuration in a .csv format
+ *                            The columns are:
+ *                            Logical PON ID, PON Mode, Physical Device ID, Physical PON ID
+ *
+ * @returns bcmos_errno
+ */
+bcmos_errno bcm_topo_init(bcm_topo_params *params, const char *topo_filename);
+
+/**
+ * @brief Returns whether the topology module has been initialized.
+ *
+ * @returns BCMOS_TRUE if topology module has been initialized
+ */
+bcmos_bool bcm_topo_is_initialized(void);
+
+#define BCM_TOPO_MAX_NNI_PORTS 16
+
+/**
+ * @brief Set the max number of nnis of a given device ID.
+ * @param device_id            device ID
+ * @param num_nni_ports        nni ports on the device
+ *
+ * @returns BCMOS_TRUE 
+ */
+bcmos_bool bcm_topo_dev_set_max_nni(bcmolt_devid device_id, uint32_t num_nni_ports);
+
+/**
+ * @brief Get the max number of nnis of a given device ID.
+ * @param device_id            device ID
+ * @param p_num_nni_ports      pointer for the retrieved nni ports on the device
+ *
+ * @returns BCMOS_TRUE 
+ */
+bcmos_bool bcm_topo_dev_get_max_nni(bcmolt_devid device_id, uint32_t *p_num_nni_ports);
+
+/**
+ * @brief Return whether a given logical NNI is in the valid range.
+ *
+ * @returns BCMOS_TRUE is the given logical NNI is in the valid range, BCMOS_FALSE otherwise
+ */
+bcmos_bool bcm_topo_nni_is_valid(uint32_t nni);
+
+#endif
+