text:
/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include "bgp/bgp_config_ifmap.h"

#include <boost/foreach.hpp>

#include <algorithm>

#include "base/string_util.h"
#include "base/task_annotations.h"
#include "bgp/bgp_common.h"
#include "bgp/bgp_config_listener.h"
#include "bgp/bgp_log.h"
#include "ifmap/ifmap_node.h"
#include "ifmap/ifmap_table.h"

#include "schema/bgp_schema_types.h"
#include "schema/vnc_cfg_types.h"

using std::auto_ptr;
using std::find;
using std::make_pair;
using std::pair;
using std::set;
using std::sort;
using std::string;
using std::vector;
using boost::iequals;

const int BgpIfmapConfigManager::kConfigTaskInstanceId = 0;

static BgpNeighborConfig::AddressFamilyList default_addr_family_list;

void DefaultAddressFamilyInit() {
    default_addr_family_list.push_back("inet");
    default_addr_family_list.push_back("inet-vpn");
}

MODULE_INITIALIZER(DefaultAddressFamilyInit);

static string IdentifierParent(const string &identifier) {
    string parent;
    size_t last;
    last = identifier.rfind(':');
    if (last == 0 || last == string::npos) {
        return parent;
    }
    parent = identifier.substr(0, last);
    return parent;
}

static uint32_t IpAddressToBgpIdentifier(const IpAddress &address) {
    return htonl(address.to_v4().to_ulong());
}

static string BgpIdentifierToString(uint32_t identifier) {
    Ip4Address addr(ntohl(identifier));
    return addr.to_string();
}

BgpIfmapPeeringConfig::BgpIfmapPeeringConfig(BgpIfmapInstanceConfig *instance)
    : instance_(instance) {
}

BgpIfmapPeeringConfig::~BgpIfmapPeeringConfig() {
    STLDeleteElements(&neighbors_);
}

void BgpIfmapPeeringConfig::SetNodeProxy(IFMapNodeProxy *proxy) {
    if (proxy != NULL) {
        node_proxy_.Swap(proxy);
        name_ = node_proxy_.node()->name();
    }
}

BgpIfmapRoutingPolicyLinkConfig::BgpIfmapRoutingPolicyLinkConfig(
    BgpIfmapInstanceConfig *rti, BgpIfmapRoutingPolicyConfig *rtp) :
     instance_(rti), policy_(rtp) {
}

BgpIfmapRoutingPolicyLinkConfig::~BgpIfmapRoutingPolicyLinkConfig() {
}

void BgpIfmapRoutingPolicyLinkConfig::SetNodeProxy(IFMapNodeProxy *proxy) {
    if (proxy != NULL) {
        node_proxy_.Swap(proxy);
        name_ = node_proxy_.node()->name();
    }
}

bool BgpIfmapRoutingPolicyLinkConfig::GetInstancePolicyPair(
    DBGraph *graph, IFMapNode *node, pair<IFMapNode *, IFMapNode *> *pair) {
    IFMapNode *routing_instance = NULL;
    IFMapNode *routing_policy = NULL;

    for (DBGraphVertex::adjacency_iterator iter = node->begin(graph);
         iter != node->end(graph); ++iter) {
        IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
        if (strcmp(adj->table()->Typename(), "routing-instance") == 0)
            routing_instance = adj;
        if (strcmp(adj->table()->Typename(), "routing-policy") == 0)
            routing_policy = adj;
    }
    if (routing_policy == NULL || routing_instance == NULL) {
        return false;
    }

    pair->first = routing_instance;
    pair->second = routing_policy;
    return true;
}

void BgpIfmapRoutingPolicyLinkConfig::Update(BgpIfmapConfigManager *manager,
    const autogen::RoutingPolicyRoutingInstance *ri_rp) {
    ri_rp_link_.reset(ri_rp);
}

void BgpIfmapRoutingPolicyLinkConfig::Delete(BgpIfmapConfigManager *manager) {
    ri_rp_link_.reset();
}

static AuthenticationData::KeyType KeyChainType(const string &value) {
    // Case-insensitive comparison
    if (boost::iequals(value, "md5")) {
        return AuthenticationData::MD5;
    }
    return AuthenticationData::NIL;
}

static void BuildKeyChain(BgpNeighborConfig *neighbor,
    const autogen::AuthenticationData &values) {
    AuthenticationData keydata;
    keydata.set_key_type(KeyChainType(values.key_type));

    AuthenticationKey key;
    for (vector<autogen::AuthenticationKeyItem>::const_iterator iter =
            values.key_items.begin(); iter != values.key_items.end(); ++iter) {
        key.id = iter->key_id;
        key.value = iter->key;
        key.start_time = 0;
        keydata.AddKeyToKeyChain(key);
    }
    neighbor->set_keydata(keydata);
}

//
// Check if the family is allowed to be configured for BgpNeighborConfig.
// Only families inet and inet6 are allowed on non-master instances.
//
static bool AddressFamilyIsValid(BgpNeighborConfig *neighbor,
    const string &family) {
    if (neighbor->instance_name() == BgpConfigManager::kMasterInstance)
        return true;
    return (family == "inet" || family == "inet6");
}

//
// Build list of BgpFamilyAttributesConfig elements from the list of address
// families. This is provided for backward compatibility with configurations
// that represent each family with a simple string.
//
static void BuildFamilyAttributesList(BgpNeighborConfig *neighbor,
    const BgpNeighborConfig::AddressFamilyList &family_list,
    const vector<string> &remote_family_list) {
    BgpNeighborConfig::FamilyAttributesList family_attributes_list;
    BOOST_FOREACH(const string &family, family_list) {
        // Skip families that are not valid/supported for the neighbor.
        if (!AddressFamilyIsValid(neighbor, family))
            continue;

        // Skip families that are not configured on remote bgp-router.
        if (!remote_family_list.empty()) {
            vector<string>::const_iterator it = find(
                remote_family_list.begin(), remote_family_list.end(), family);
            if (it == remote_family_list.end())
                continue;
        }

        BgpFamilyAttributesConfig family_attributes(family);
        family_attributes_list.push_back(family_attributes);
    }

    neighbor->set_family_attributes_list(family_attributes_list);
}

//
// Build list of BgpFamilyAttributesConfig elements from BgpFamilyAttributes
// list in BgpSessionAttributes.
//
// Implement backward compatibility by also adding BgpFamilyAttributesConfig
// elements for families that are not in BgpFamilyAttributes list but are in
// the address_families list.
//
static void BuildFamilyAttributesList(BgpNeighborConfig *neighbor,
    const autogen::BgpSessionAttributes *attributes) {
    set<string> family_set;
    BgpNeighborConfig::FamilyAttributesList family_attributes_list;
    BOOST_FOREACH(const autogen::BgpFamilyAttributes &family_config,
        attributes->family_attributes) {
        if (!AddressFamilyIsValid(neighbor, family_config.address_family))
            continue;
        BgpFamilyAttributesConfig family_attributes(
            family_config.address_family);
        family_attributes.loop_count = family_config.loop_count;
        family_attributes.prefix_limit = family_config.prefix_limit.maximum;
        family_attributes_list.push_back(family_attributes);
        family_set.insert(family_config.address_family);
    }

    BOOST_FOREACH(const string &family, attributes->address_families.family) {
        if (family_set.find(family) != family_set.end())
            continue;
        BgpFamilyAttributesConfig family_attributes(family);
        family_attributes_list.push_back(family_attributes);
    }

    neighbor->set_family_attributes_list(family_attributes_list);
}

//
// Set the autogen::BgpSessionAttributes for this BgpNeighborConfig.
//
// The autogen::BgpSession will have up to 3 session attributes - one that
// applies to the local router, one that applies the remote router and one
// that applies to both.
//
static void NeighborSetSessionAttributes(
    BgpNeighborConfig *neighbor, const string &localname,
    const autogen::BgpSession *session) {
    typedef vector<autogen::BgpSessionAttributes> AttributeVec;
    const autogen::BgpSessionAttributes *common = NULL;
    const autogen::BgpSessionAttributes *local = NULL;
    for (AttributeVec::const_iterator iter = session->attributes.begin();
         iter != session->attributes.end(); ++iter) {
        const autogen::BgpSessionAttributes *attr = iter.operator->();
        if (attr->bgp_router.empty()) {
            common = attr;
        } else if (neighbor->router_type() != "bgpaas-client" &&
            attr->bgp_router == localname) {
            local = attr;
        } else if (neighbor->router_type() == "bgpaas-client" &&
            attr->bgp_router == "bgpaas-server") {
            local = attr;
        }
    }

    // TODO(nsheth): local should override rather than replace common.
    const autogen::BgpSessionAttributes *attributes = NULL;
    if (common != NULL) {
        attributes = common;
    } else if (local != NULL) {
        attributes = local;
    }
    if (attributes != NULL) {
        neighbor->set_passive(attributes->passive);
        neighbor->set_as_override(attributes->as_override);
        neighbor->set_private_as_action(attributes->private_as_action);
        neighbor->set_loop_count(attributes->loop_count);
        if (attributes->admin_down) {
            neighbor->set_admin_down(true);
        }
        if (attributes->hold_time) {
            neighbor->set_hold_time(attributes->hold_time);
        }
        BuildFamilyAttributesList(neighbor, attributes);
        BuildKeyChain(neighbor, attributes->auth_data);
    }
}

static BgpNeighborConfig *MakeBgpNeighborConfig(
    const BgpIfmapInstanceConfig *instance,
    const BgpIfmapInstanceConfig *master_instance,
    const string &local_name,
    const string &remote_name,
    const autogen::BgpRouter *local_router,
    const autogen::BgpRouter *remote_router,
    const autogen::BgpSession *session) {
    BgpNeighborConfig *neighbor = new BgpNeighborConfig();

    neighbor->set_instance_name(instance->name());

    // If the autogen::BgpSession has a uuid, we append it to the remote
    // bgp-router's name to make the BgpNeighborConfig's name unique.
    if (session && !session->uuid.empty()) {
        neighbor->set_uuid(session->uuid);
        neighbor->set_name(remote_name + ":" + session->uuid);
    } else {
        neighbor->set_name(remote_name);
    }

    // Store a copy of the remote bgp-router's autogen::BgpRouterParams and
    // derive the autogen::BgpSessionAttributes for the session.
    const autogen::BgpRouterParams &params = remote_router->parameters();
    neighbor->set_router_type(params.router_type);
    if (params.admin_down) {
        neighbor->set_admin_down(true);
    }
    if (params.local_autonomous_system) {
        neighbor->set_peer_as(params.local_autonomous_system);
    } else {
        neighbor->set_peer_as(params.autonomous_system);
    }
    boost::system::error_code err;
    neighbor->set_peer_address(
        IpAddress::from_string(params.address, err));
    if (err) {
        BGP_LOG_WARNING_STR(BgpConfig, BGP_LOG_FLAG_ALL,
                            "Invalid peer address " << params.address <<
                            " for neighbor " << neighbor->name());
    }

    Ip4Address identifier = Ip4Address::from_string(params.identifier, err);
    if (err) {
        BGP_LOG_WARNING_STR(BgpConfig, BGP_LOG_FLAG_ALL,
                            "Invalid peer identifier " << params.identifier <<
                            " for neighbor " << neighbor->name());
    }
    neighbor->set_peer_identifier(IpAddressToBgpIdentifier(identifier));

    if (params.router_type == "bgpaas-client") {
        IpAddress inet_gw_address =
            Ip4Address::from_string(params.gateway_address, err);
        if (!params.gateway_address.empty() && err) {
            BGP_LOG_WARNING_STR(BgpConfig, BGP_LOG_FLAG_ALL,
                                "Invalid gateway address " <<
                                params.gateway_address <<
                                " for neighbor " << neighbor->name());
        } else {
            neighbor->set_gateway_address(Address::INET, inet_gw_address);
        }

        IpAddress inet6_gw_address =
            Ip6Address::from_string(params.ipv6_gateway_address, err);
        if (!params.ipv6_gateway_address.empty() && err) {
            BGP_LOG_WARNING_STR(BgpConfig, BGP_LOG_FLAG_ALL,
                "Invalid ipv6 gateway address " <<
                params.ipv6_gateway_address <<
                " for neighbor " << neighbor->name());
        } else {
            neighbor->set_gateway_address(Address::INET6, inet6_gw_address);
        }
    }

    neighbor->set_port(params.port);
    neighbor->set_source_port(params.source_port);
    neighbor->set_hold_time(params.hold_time);

    if (session != NULL) {
        NeighborSetSessionAttributes(neighbor, local_name, session);
    }

    // Get the local identifier and local as from the master protocol config.
    const BgpIfmapProtocolConfig *master_protocol =
        master_instance->protocol_config();
    if (master_protocol && master_protocol->bgp_router()) {
        const autogen::BgpRouterParams &master_params =
            master_protocol->router_params();
        if (master_params.admin_down) {
            neighbor->set_admin_down(true);
        }
        Ip4Address localid =
            Ip4Address::from_string(master_params.identifier, err);
        if (err == 0) {
            neighbor->set_local_identifier(IpAddressToBgpIdentifier(localid));
        }
        if (master_params.local_autonomous_system) {
            neighbor->set_local_as(master_params.local_autonomous_system);
        } else {
            neighbor->set_local_as(master_params.autonomous_system);
        }
        if (instance != master_instance) {
            neighbor->set_passive(true);
        }
    }

    // Get other parameters from the instance protocol config.
    // Note that there's no instance protocol config for non-master instances.
    const BgpIfmapProtocolConfig *protocol = instance->protocol_config();
    if (protocol && protocol->bgp_router()) {
        const autogen::BgpRouterParams &protocol_params =
            protocol->router_params();
        if (neighbor->family_attributes_list().empty()) {
            BuildFamilyAttributesList(neighbor,
                protocol_params.address_families.family,
                params.address_families.family);
        }
        if (neighbor->auth_data().Empty()) {
            const autogen::BgpRouterParams &local_params =
                local_router->parameters();
            BuildKeyChain(neighbor, local_params.auth_data);
        }
    }

    if (neighbor->family_attributes_list().empty()) {
        BuildFamilyAttributesList(neighbor, default_addr_family_list,
            params.address_families.family);
    }

    return neighbor;
}

//
// Build map of BgpNeighborConfigs based on the data in autogen::BgpPeering.
//
void BgpIfmapPeeringConfig::BuildNeighbors(BgpIfmapConfigManager *manager,
    const autogen::BgpRouter *local_rt_config,
    const string &peername, const autogen::BgpRouter *remote_rt_config,
    const autogen::BgpPeering *peering, NeighborMap *map) {
    const BgpIfmapInstanceConfig *master_instance =
        manager->config()->FindInstance(BgpConfigManager::kMasterInstance);

    // If there are one or more autogen::BgpSessions for the peering, use
    // those to create the BgpNeighborConfigs.
    const autogen::BgpPeeringAttributes &attr = peering->data();
    for (autogen::BgpPeeringAttributes::const_iterator iter = attr.begin();
         iter != attr.end(); ++iter) {
        BgpNeighborConfig *neighbor = MakeBgpNeighborConfig(
            instance_, master_instance, manager->localname(), peername,
            local_rt_config, remote_rt_config, iter.operator->());
        map->insert(make_pair(neighbor->name(), neighbor));
    }

    // When no sessions are present, create a single BgpNeighborConfig with
    // no per-session configuration.
    if (map->empty()) {
        BgpNeighborConfig *neighbor = MakeBgpNeighborConfig(
            instance_, master_instance, manager->localname(), peername,
            local_rt_config, remote_rt_config, NULL);
        map->insert(make_pair(neighbor->name(), neighbor));
    }
}

//
// Update BgpIfmapPeeringConfig based on updated autogen::BgpPeering.
//
// This mainly involves building future BgpNeighborConfigs and doing a diff of
// the current and future BgpNeighborConfigs.  Note that BgpIfmapInstanceConfig
// also has references to BgpNeighborConfigs, so it also needs to be updated as
// part of the process.
//
void BgpIfmapPeeringConfig::Update(BgpIfmapConfigManager *manager,
    const autogen::BgpPeering *peering) {
    IFMapNode *node = node_proxy_.node();
    assert(node != NULL);
    bgp_peering_.reset(peering);

    // Build the future NeighborMap.  The future map should be empty if the
    // bgp-peering is deleted or if the parameters for the remote bgp-router
    // are not available.
    NeighborMap future;
    pair<IFMapNode *, IFMapNode *> routers;
    if (!node->IsDeleted() &&
        GetRouterPair(manager->graph(), manager->localname(), node, &routers)) {
        const autogen::BgpRouter *local_rt_config =
                static_cast<const autogen::BgpRouter *>(
                    routers.first->GetObject());
        const autogen::BgpRouter *remote_rt_config =
                static_cast<const autogen::BgpRouter *>(
                    routers.second->GetObject());
        if (local_rt_config &&
            local_rt_config->IsPropertySet(autogen::BgpRouter::PARAMETERS) &&
            remote_rt_config &&
            remote_rt_config->IsPropertySet(autogen::BgpRouter::PARAMETERS)) {
            BuildNeighbors(manager, local_rt_config, routers.second->name(),
                           remote_rt_config, peering, &future);
        }
    }

    // Swap out the NeighborMap in preparation for doing a diff.
    NeighborMap current;
    current.swap(neighbors_);

    // Do a diff on the current and future BgpNeighborConfigs, making sure
    // that the BgpIfmapInstanceConfig is updated accordingly.  We add any new
    // BgpNeighborConfigs to our NeighborMap.
    NeighborMap::iterator it1 = current.begin();
    NeighborMap::iterator it2 = future.begin();
    while (it1 != current.end() && it2 != future.end()) {
        if (it1->first < it2->first) {
            BgpNeighborConfig *prev = it1->second;
            instance_->DeleteNeighbor(manager, prev);
            ++it1;
        } else if (it1->first > it2->first) {
            BgpNeighborConfig *neighbor = it2->second;
            instance_->AddNeighbor(manager, neighbor);
            neighbors_.insert(*it2);
            it2->second = NULL;
            ++it2;
        } else {
            BgpNeighborConfig *neighbor = it1->second;
            BgpNeighborConfig *update = it2->second;
            if (*neighbor != *update) {
                instance_->ChangeNeighbor(manager, update);
                neighbors_.insert(*it2);
                it2->second = NULL;
            } else {
                neighbors_.insert(*it1);
                it1->second = NULL;
            }
            ++it1;
            ++it2;
        }
    }
    for (; it1 != current.end(); ++it1) {
        BgpNeighborConfig *prev = it1->second;
        instance_->DeleteNeighbor(manager, prev);
    }
    for (; it2 != future.end(); ++it2) {
        BgpNeighborConfig *neighbor = it2->second;
        instance_->AddNeighbor(manager, neighbor);
        neighbors_.insert(*it2);
        it2->second = NULL;
    }

    // Get rid of the current and future NeighborMaps and destroy any mapped
    // BgpNeighborConfigs. Note that we have carefully reset mapped values to
    // NULL above when we don't want a BgpNeighborConfig to get destroyed.
    STLDeleteElements(&current);
    STLDeleteElements(&future);
}

//
// Delete all state for the given BgpPeeringConfig.
//
// This mainly involves getting rid of BgpNeighborConfigs in the NeighborMap.
//
void BgpIfmapPeeringConfig::Delete(BgpIfmapConfigManager *manager) {
    NeighborMap current;
    current.swap(neighbors_);
    for (NeighborMap::iterator iter = current.begin();
         iter != current.end(); ++iter) {
        instance_->DeleteNeighbor(manager, iter->second);
    }
    STLDeleteElements(&current);
    bgp_peering_.reset();
}

//
// Find the IFMapNodes for a bgp-peering.
//
// The "node" is the IFMapNode for the bgp-peering link.  The bgp-peering is
// interesting only if one of the bgp-routers is the local node.
//
// Return true if both bgp-routers for the bgp-peering exist and one of them
// is the local one. Also fill in the local and remote IFMapNode pointers if
// we return true.
//
bool BgpIfmapPeeringConfig::GetRouterPair(DBGraph *db_graph,
    const string  &localname, IFMapNode *node,
    pair<IFMapNode *, IFMapNode *> *pair) {
    IFMapNode *local = NULL;
    IFMapNode *remote = NULL;
    string local_router_type;
    string remote_router_type;
    string local_instance;
    string remote_instance;

    for (DBGraphVertex::adjacency_iterator iter = node->begin(db_graph);
         iter != node->end(db_graph); ++iter) {
        IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
        if (strcmp(adj->table()->Typename(), "bgp-router") != 0)
            continue;
        autogen::BgpRouter *router =
            static_cast<autogen::BgpRouter *>(adj->GetObject());
        if (!router)
            continue;
        const autogen::BgpRouterParams &params = router->parameters();
        string instance_name(IdentifierParent(adj->name()));
        string name = adj->name().substr(instance_name.size() + 1);
        if (name == localname && params.router_type != "bgpaas-client") {
            local = adj;
            local_router_type = params.router_type;
            local_instance = instance_name;
        } else if (instance_name != BgpConfigManager::kMasterInstance &&
            params.router_type == "bgpaas-server") {
            local = adj;
            local_router_type = params.router_type;
            local_instance = instance_name;
        } else {
            remote = adj;
            remote_router_type = params.router_type;
            remote_instance = instance_name;
        }
    }
    if (local == NULL || remote == NULL) {
        return false;
    }
    if (local_router_type == "bgpaas-server" &&
        remote_router_type != "bgpaas-client") {
        return false;
    }
    if (local_router_type != "bgpaas-server" &&
        remote_router_type == "bgpaas-client") {
        return false;
    }
    if (local_instance != remote_instance) {
        return false;
    }

    pair->first = local;
    pair->second = remote;
    return true;
}

//
// Constructor for BgpIfmapProtocolConfig.
//
BgpIfmapProtocolConfig::BgpIfmapProtocolConfig(BgpIfmapInstanceConfig *instance)
    : instance_(instance),
      data_(instance->name()) {
}

//
// Destructor for BgpIfmapProtocolConfig.
//
BgpIfmapProtocolConfig::~BgpIfmapProtocolConfig() {
}

const autogen::BgpRouterParams &BgpIfmapProtocolConfig::router_params() const {
    return bgp_router_->parameters();
}

//
// Set the IFMapNodeProxy for the BgpIfmapProtocolConfig.
//
void BgpIfmapProtocolConfig::SetNodeProxy(IFMapNodeProxy *proxy) {
    if (proxy != NULL) {
        node_proxy_.Swap(proxy);
    }
}

//
// Update autogen::BgpRouter object for this BgpIfmapProtocolConfig.
//
void BgpIfmapProtocolConfig::Update(BgpIfmapConfigManager *manager,
    const autogen::BgpRouter *router) {
    bgp_router_.reset(router);
    const autogen::BgpRouterParams &params = router->parameters();
    data_.set_admin_down(params.admin_down);
    data_.set_autonomous_system(params.autonomous_system);
    data_.set_local_autonomous_system(params.local_autonomous_system);
    boost::system::error_code err;
    IpAddress identifier = IpAddress::from_string(params.identifier, err);
    if (err == 0) {
        data_.set_identifier(IpAddressToBgpIdentifier(identifier));
    }
    data_.set_hold_time(params.hold_time);
}

//
// Delete autogen::BgpRouter object for this BgpIfmapProtocolConfig.
//
void BgpIfmapProtocolConfig::Delete(BgpIfmapConfigManager *manager) {
    manager->Notify(&data_, BgpConfigManager::CFG_DELETE);
    bgp_router_.reset();
}

const string &BgpIfmapProtocolConfig::InstanceName() const {
    return instance_->name();
}

//
// Constructor for BgpIfmapInstanceConfig.
//
BgpIfmapInstanceConfig::BgpIfmapInstanceConfig(const string &name)
    : name_(name),
      data_(name),
      protocol_(NULL) {
}

//
// Destructor for BgpIfmapInstanceConfig.
//
BgpIfmapInstanceConfig::~BgpIfmapInstanceConfig() {
}

//
// Set the IFMapNodeProxy for the BgpIfmapInstanceConfig.
//
void BgpIfmapInstanceConfig::SetNodeProxy(IFMapNodeProxy *proxy) {
    if (proxy != NULL) {
        node_proxy_.Swap(proxy);
    }
}

//
// Get the BgpIfmapProtocolConfig for this BgpIfmapInstanceConfig, create
// it if needed.
//
BgpIfmapProtocolConfig *BgpIfmapInstanceConfig::LocateProtocol() {
    if (protocol_.get() == NULL) {
        protocol_.reset(new BgpIfmapProtocolConfig(this));
    }
    return protocol_.get();
}

//
// Delete the BgpIfmapProtocolConfig for this BgpIfmapInstanceConfig.
//
void BgpIfmapInstanceConfig::ResetProtocol() {
    protocol_.reset();
}

//
// Get the route-target for an instance-target. The input IFMapNode is the
// midnode that represents the instance-target link. We traverse the graph
// the graph edges till we find the adjacency to the route-target.
//
// Return true and fill in the target string if we find the route-target.
//
static bool GetInstanceTargetRouteTarget(DBGraph *graph, IFMapNode *node,
    string *target) {
    for (DBGraphVertex::adjacency_iterator iter = node->begin(graph);
         iter != node->end(graph); ++iter) {
        IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
        if (strcmp(adj->table()->Typename(), "route-target") == 0) {
            *target = adj->name();
            return true;
        }
    }
    return false;
}

//
// Fill in all the export route targets for a routing-instance.  The input
// IFMapNode represents the routing-instance.  We traverse the graph edges
// and look for instance-target adjacencies. If the instance-target is an
// export and import target, add it to the vector.
//
// Note that we purposely skip adding export only targets to the vector.
// Reasoning is that export only targets are manually configured by users
// and hence should not be imported based on policy.
//
static void GetRoutingInstanceExportTargets(DBGraph *graph, IFMapNode *node,
    vector<string> *target_list) {
    for (DBGraphVertex::adjacency_iterator iter = node->begin(graph);
         iter != node->end(graph); ++iter) {
        IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
        string target;
        if ((strcmp(adj->table()->Typename(), "instance-target") == 0) &&
            (GetInstanceTargetRouteTarget(graph, adj, &target))) {
            const autogen::InstanceTarget *itarget =
                    dynamic_cast<autogen::InstanceTarget *>(adj->GetObject());
            if (!itarget)
                continue;
            const autogen::InstanceTargetType &itt = itarget->data();
            if (itt.import_export.empty())
                target_list->push_back(target);
        }
    }
}

//
// Fill in all the export route targets of the routing-instance at the other
// end of a connection.  The src_node is the routing-instance from which we
// reached the connection node. The name of the source routing-instance is
// src_instance.
//
// If the connection is unidirectional and the destination-instance for the
// connection is not the routing-instance from which we started, we should
// not get any targets from this connection.  This is what a unidirectional
// connection means.
//
static void GetConnectionExportTargets(DBGraph *graph, IFMapNode *src_node,
    const string &src_instance, IFMapNode *node,
    vector<string> *target_list) {
    const autogen::Connection *conn =
        dynamic_cast<autogen::Connection *>(node->GetObject());
    if (!conn)
        return;
    const autogen::ConnectionType &conn_type = conn->data();
    if (!conn_type.destination_instance.empty() &&
         conn_type.destination_instance != src_instance)
        return;
    for (DBGraphVertex::adjacency_iterator iter = node->begin(graph);
         iter != node->end(graph); ++iter) {
        IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
        if (adj == src_node)
            continue;
        if (strcmp(adj->table()->Typename(), "routing-instance") != 0)
            continue;
        GetRoutingInstanceExportTargets(graph, adj, target_list);
    }
}

//
// Fill in all the routing-policies for a routing-instance.  The input
// IFMapNode represents the routing-policy-routing-instance.  We traverse to
// graph edges and look for routing-policy adjacency
//
static bool GetRoutingInstanceRoutingPolicy(DBGraph *graph, IFMapNode *node,
    RoutingPolicyAttachInfo *ri_rp_link) {
    string sequence;
    const autogen::RoutingPolicyRoutingInstance *policy =
        static_cast<autogen::RoutingPolicyRoutingInstance *>(node->GetObject());
    const autogen::RoutingPolicyType &attach_info = policy->data();

    ri_rp_link->sequence_ = attach_info.sequence;

    for (DBGraphVertex::adjacency_iterator iter = node->begin(graph);
         iter != node->end(graph); ++iter) {
        IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
        if (strcmp(adj->table()->Typename(), "routing-policy") == 0) {
            ri_rp_link->routing_policy_ = adj->name();
            return true;
        }
    }
    return false;
}

//
// Fill in all the route-aggregation for a routing-instance.
//
static bool GetRouteAggregateConfig(DBGraph *graph, IFMapNode *node,
    BgpInstanceConfig::AggregateRouteList *inet_list,
    BgpInstanceConfig::AggregateRouteList *inet6_list) {
    const autogen::RouteAggregate *ra =
        static_cast<autogen::RouteAggregate *>(node->GetObject());
    if (ra == NULL) return false;

    boost::system::error_code ec;
    IpAddress nexthop =
        IpAddress::from_string(ra->aggregate_route_nexthop(), ec);
    if (ec != 0) return false;

    BOOST_FOREACH(const string &route, ra->aggregate_route_entries()) {
        AggregateRouteConfig aggregate;
        aggregate.nexthop = nexthop;

        Ip4Address address;
        ec = Ip4SubnetParse(route, &address, &aggregate.prefix_length);
        if (ec == 0) {
            if (!nexthop.is_v4()) continue;
            aggregate.aggregate = address;
            inet_list->push_back(aggregate);
        } else {
            if (!nexthop.is_v6()) continue;
            Ip6Address address;
            ec = Inet6SubnetParse(route, &address, &aggregate.prefix_length);
            if (ec != 0) continue;
            aggregate.aggregate = address;
            inet6_list->push_back(aggregate);
        }
    }

    return true;
}

//
// Get the network id for a virtual-network.  The input IFMapNode represents
// the virtual-network.
//
static int GetVirtualNetworkIndex(DBGraph *graph, IFMapNode *node) {
    const autogen::VirtualNetwork *vn =
        static_cast<autogen::VirtualNetwork *>(node->GetObject());
    if (vn && vn->IsPropertySet(autogen::VirtualNetwork::NETWORK_ID))
        return vn->network_id();
    if (vn && vn->IsPropertySet(autogen::VirtualNetwork::PROPERTIES))
        return vn->properties().network_id;
    return 0;
}

//
// Check if a virtual-network allows transit. The input IFMapNode represents
// the virtual-network.
//
static bool GetVirtualNetworkAllowTransit(DBGraph *graph, IFMapNode *node) {
    const autogen::VirtualNetwork *vn =
        static_cast<autogen::VirtualNetwork *>(node->GetObject());
    if (vn && vn->IsPropertySet(autogen::VirtualNetwork::PROPERTIES))
        return vn->properties().allow_transit;
    return false;
}

//
// Check if a virtual-network has pbb-evpn enabled.
// The input IFMapNode represents the virtual-network.
//
static bool GetVirtualNetworkPbbEvpnEnable(DBGraph *graph, IFMapNode *node) {
    const autogen::VirtualNetwork *vn =
        static_cast<autogen::VirtualNetwork *>(node->GetObject());
    if (vn && vn->IsPropertySet(autogen::VirtualNetwork::PBB_EVPN_ENABLE))
        return vn->pbb_evpn_enable();
    return false;
}

//
// Get the vxlan id for a virtual-network.  The input IFMapNode represents
// the virtual-network.
//
// The vxlan_network_identifier is 0 when automatic mode is in use. In that
// case, the network_id is used as vxlan id.
//
static int GetVirtualNetworkVxlanId(DBGraph *graph, IFMapNode *node) {
    const autogen::VirtualNetwork *vn =
        static_cast<autogen::VirtualNetwork *>(node->GetObject());
    if (vn && vn->IsPropertySet(autogen::VirtualNetwork::PROPERTIES)) {
        if (vn->properties().vxlan_network_identifier) {
            return vn->properties().vxlan_network_identifier;
        } else {
            return vn->properties().network_id;
        }
    }
    return 0;
}

static void SetStaticRouteConfig(BgpInstanceConfig *rti,
    const autogen::RoutingInstance *config) {
    BgpInstanceConfig::StaticRouteList inet_list;
    BgpInstanceConfig::StaticRouteList inet6_list;
    BOOST_FOREACH(const autogen::StaticRouteType &route,
                  config->static_route_entries()) {
        boost::system::error_code ec;
        StaticRouteConfig item;
        item.nexthop = IpAddress::from_string(route.next_hop, ec);
        if (ec != 0)
            continue;

        item.route_targets = route.route_target;
        item.communities = route.community;
        if (item.nexthop.is_v4()) {
            Ip4Address address;
            ec = Ip4SubnetParse(route.prefix, &address, &item.prefix_length);
            if (ec != 0)
                continue;
            item.address = address;
            std::pair<BgpInstanceConfig::StaticRouteList::iterator, bool> ret =
                inet_list.insert(item);
            if (!ret.second) {
                BGP_LOG_WARNING_STR(BgpConfig, BGP_LOG_FLAG_ALL,
                    "Duplicate static route prefix " << route.prefix <<
                    " with nexthop " << route.next_hop <<
                    " for routing instance " << rti->name());
            }
        } else {
            Ip6Address address;
            ec = Inet6SubnetParse(route.prefix, &address, &item.prefix_length);
            if (ec != 0)
                continue;
            item.address = address;
            std::pair<BgpInstanceConfig::StaticRouteList::iterator, bool> ret =
                inet6_list.insert(item);
            if (!ret.second) {
                BGP_LOG_WARNING_STR(BgpConfig, BGP_LOG_FLAG_ALL,
                    "Duplicate static route prefix " << route.prefix <<
                    " with nexthop " << route.next_hop <<
                    " for routing instance " << rti->name());
            }
        }
    }
    rti->swap_static_routes(Address::INET, &inet_list);
    rti->swap_static_routes(Address::INET6, &inet6_list);
}

static void SetServiceChainConfig(BgpInstanceConfig *rti,
    const autogen::RoutingInstance *config) {
    BgpInstanceConfig::ServiceChainList list;
    const autogen::ServiceChainInfo &inet_chain =
        config->service_chain_information();
    if (config->IsPropertySet(
        autogen::RoutingInstance::SERVICE_CHAIN_INFORMATION)) {
        ServiceChainConfig item = {
            Address::INET,
            inet_chain.routing_instance,
            inet_chain.prefix,
            inet_chain.service_chain_address,
            inet_chain.service_instance,
            inet_chain.source_routing_instance
        };
        list.push_back(item);
    }

    const autogen::ServiceChainInfo &inet6_chain =
        config->ipv6_service_chain_information();
    if (config->IsPropertySet(
        autogen::RoutingInstance::IPV6_SERVICE_CHAIN_INFORMATION)) {
        ServiceChainConfig item = {
            Address::INET6,
            inet6_chain.routing_instance,
            inet6_chain.prefix,
            inet6_chain.service_chain_address,
            inet6_chain.service_instance,
            inet6_chain.source_routing_instance
        };
        list.push_back(item);
    }

    rti->swap_service_chain_list(&list);
}

void BgpIfmapConfigManager::ProcessRoutingPolicyLink(
    const BgpConfigDelta &delta) {
    CHECK_CONCURRENCY("bgp::Config");

    BgpIfmapRoutingPolicyLinkConfig *ri_rp_link
        = config_->FindRoutingPolicyLink(delta.id_name);
    if (ri_rp_link == NULL) {
        IFMapNodeProxy *proxy = delta.node.get();
        if (proxy == NULL) {
            return;
        }
        IFMapNode *node = proxy->node();
        if (node == NULL || delta.obj.get() == NULL) {
            return;
        }

        pair<IFMapNode *, IFMapNode *> ri_rp_pair;
        if (!BgpIfmapRoutingPolicyLinkConfig::GetInstancePolicyPair(db_graph_,
            node, &ri_rp_pair)) {
            return;
        }

        string instance_name = ri_rp_pair.first->name();
        string policy_name = ri_rp_pair.second->name();

        BgpIfmapInstanceConfig *rti  =
            config_->FindInstance(instance_name);
        BgpIfmapRoutingPolicyConfig *rtp  =
            config_->FindRoutingPolicy(policy_name);
        if (!rti || !rtp) {
            return;
        }

        ri_rp_link = config_->CreateRoutingPolicyLink(rti, rtp, proxy);
    } else {
        const IFMapNode *node = ri_rp_link->node();
        assert(node != NULL);
        if (delta.obj.get() == NULL) {
            BgpIfmapRoutingPolicyConfig *rtp = ri_rp_link->policy();
            BgpIfmapInstanceConfig *rti = ri_rp_link->instance();
            config_->DeleteRoutingPolicyLink(ri_rp_link);
            if (rtp->DeleteIfEmpty(this)) {
                config_->DeleteRoutingPolicy(rtp);
            }
            if (rti->DeleteIfEmpty(this)) {
                BGP_CONFIG_LOG_INSTANCE(Delete, server(), rti,
                    SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL);
                config_->DeleteInstance(rti);
            }
            return;
        }
    }

    autogen::RoutingPolicyRoutingInstance *ri_rp_link_cfg =
        static_cast<autogen::RoutingPolicyRoutingInstance *>(delta.obj.get());

    ri_rp_link->Update(this, ri_rp_link_cfg);
}

static bool CompareRoutingPolicyOrder(const RoutingPolicyAttachInfo &lhs,
                                      const RoutingPolicyAttachInfo &rhs) {
    return (lhs.sequence_ < rhs.sequence_);
}

//
// Update BgpIfmapInstanceConfig based on a new autogen::RoutingInstance object.
//
// Rebuild the import and export route target lists and update the virtual
// network information.
//
// Targets that are configured on this routing-instance (which corresponds
// to all adjacencies to instance-target) are added to the import list or
// export list or both depending on the import_export attribute.
//
// Export targets for all other routing-instances that we are connected to
// are added to our import list.
//
void BgpIfmapInstanceConfig::Update(BgpIfmapConfigManager *manager,
    const autogen::RoutingInstance *config) {
    BgpInstanceConfig::RouteTargetList import_list, export_list;
    BgpInstanceConfig::AggregateRouteList inet6_aggregate_list;
    BgpInstanceConfig::AggregateRouteList inet_aggregate_list;
    RoutingPolicyConfigList policy_list;
    data_.Clear();

    DBGraph *graph = manager->graph();
    IFMapNode *node = node_proxy_.node();
    for (DBGraphVertex::adjacency_iterator iter = node->begin(graph);
         iter != node->end(graph); ++iter) {
        IFMapNode *adj = static_cast<IFMapNode *>(iter.operator->());
        if (strcmp(adj->table()->Typename(), "instance-target") == 0) {
            string target;
            if (GetInstanceTargetRouteTarget(graph, adj, &target)) {
                const autogen::InstanceTarget *itarget =
                    dynamic_cast<autogen::InstanceTarget *>(adj->GetObject());
                if (!itarget)
                    continue;
                const autogen::InstanceTargetType &itt = itarget->data();
                if (itt.import_export == "import") {
                    import_list.insert(target);
                } else if (itt.import_export == "export") {
                    export_list.insert(target);
                } else {
                    import_list.insert(target);
                    export_list.insert(target);
                }
            }
        } else if (strcmp(adj->table()->Typename(),
                          "routing-policy-routing-instance") == 0) {
            RoutingPolicyAttachInfo policy_info;
            if (GetRoutingInstanceRoutingPolicy(graph, adj, &policy_info)) {
                policy_list.push_back(policy_info);
            }
        } else if (strcmp(adj->table()->Typename(), "route-aggregate") == 0) {
            GetRouteAggregateConfig(graph, adj, &inet_aggregate_list,
                                    &inet6_aggregate_list);
        } else if (strcmp(adj->table()->Typename(), "connection") == 0) {
            vector<string> target_list;
            GetConnectionExportTargets(graph, node, name_, adj, &target_list);
            BOOST_FOREACH(string target, target_list) {
                import_list.insert(target);
            }
        } else if (strcmp(adj->table()->Typename(), "virtual-network") == 0) {
            data_.set_virtual_network(adj->name());
            data_.set_virtual_network_index(GetVirtualNetworkIndex(graph, adj));
            data_.set_virtual_network_allow_transit(
                GetVirtualNetworkAllowTransit(graph, adj));
            data_.set_vxlan_id(GetVirtualNetworkVxlanId(graph, adj));
            data_.set_virtual_network_pbb_evpn_enable(
                GetVirtualNetworkPbbEvpnEnable(graph, adj));
        }
    }

    data_.set_import_list(import_list);
    data_.set_export_list(export_list);

    sort(policy_list.begin(), policy_list.end(), CompareRoutingPolicyOrder);
    data_.swap_routing_policy_list(&policy_list);
    data_.swap_aggregate_routes(Address::INET, &inet_aggregate_list);
    data_.swap_aggregate_routes(Address::INET6, &inet6_aggregate_list);

    if (config) {
        data_.set_has_pnf(config->has_pnf());
        SetStaticRouteConfig(&data_, config);
        SetServiceChainConfig(&data_, config);
    }
}

//
// Reset IFMap related state in the BgpIfmapInstanceConfig.
//
void BgpIfmapInstanceConfig::ResetConfig() {
    node_proxy_.Clear();
}

//
// Return true if the BgpIfmapInstanceConfig is ready to be deleted.  The
// caller is responsible for actually deleting it.
//
bool BgpIfmapInstanceConfig::DeleteIfEmpty(BgpConfigManager *manager) {
    if (name_ == BgpConfigManager::kMasterInstance) {
        return false;
    }
    if (node() != NULL || protocol_.get() != NULL) {
        return false;
    }
    if (!neighbors_.empty() || !peerings_.empty() ||
        !routing_policies_.empty()) {
        return false;
    }

    manager->Notify(&data_, BgpConfigManager::CFG_DELETE);
    return true;
}

//
// Add a BgpNeighborConfig to this BgpIfmapInstanceConfig.
//
// The BgpNeighborConfig is added to the NeighborMap and the BgpConfigManager
// is notified.
//
void BgpIfmapInstanceConfig::AddNeighbor(BgpConfigManager *manager,
    BgpNeighborConfig *neighbor) {
    BGP_CONFIG_LOG_NEIGHBOR(
        Create, manager->server(), neighbor, SandeshLevel::SYS_DEBUG,
        BGP_LOG_FLAG_ALL,
        neighbor->admin_down(),
        neighbor->passive(),
        BgpIdentifierToString(neighbor->local_identifier()),
        neighbor->local_as(),
        neighbor->peer_address().to_string(), neighbor->peer_as(),
        neighbor->GetAddressFamilies(), neighbor->AuthKeyTypeToString(),
        neighbor->AuthKeysToString());
    neighbors_.insert(make_pair(neighbor->name(), neighbor));
    data_.add_neighbor(neighbor->name());
    manager->Notify(neighbor, BgpConfigManager::CFG_ADD);
}

//
// Change a BgpNeighborConfig that's already in this BgpIfmapInstanceConfig.
//
void BgpIfmapInstanceConfig::ChangeNeighbor(BgpConfigManager *manager,
    BgpNeighborConfig *neighbor) {
    NeighborMap::iterator loc = neighbors_.find(neighbor->name());
    assert(loc != neighbors_.end());
    loc->second = neighbor;

    BGP_CONFIG_LOG_NEIGHBOR(
        Update, manager->server(), neighbor,
        SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
        neighbor->admin_down(),
        neighbor->passive(),
        BgpIdentifierToString(neighbor->local_identifier()),
        neighbor->local_as(),
        neighbor->peer_address().to_string(), neighbor->peer_as(),
        neighbor->GetAddressFamilies(), neighbor->AuthKeyTypeToString(),
        neighbor->AuthKeysToString());
    manager->Notify(neighbor, BgpConfigManager::CFG_CHANGE);
}

//
// Delete a BgpNeighborConfig from this BgpIfmapInstanceConfig.
//
// The BgpConfigManager is notified and BgpNeighborConfig is removed from the
// NeighborMap. Note that the caller is responsible for actually deleting the
// BgpNeighborConfig object.
//
void BgpIfmapInstanceConfig::DeleteNeighbor(BgpConfigManager *manager,
    BgpNeighborConfig *neighbor) {
    BGP_CONFIG_LOG_NEIGHBOR(Delete, manager->server(), neighbor,
        SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL);
    manager->Notify(neighbor, BgpConfigManager::CFG_DELETE);
    neighbors_.erase(neighbor->name());
    data_.delete_neighbor(neighbor->name());
}

//
// Find the BgpNeighborConfig by name in this BgpIfmapInstanceConfig.
//
const BgpNeighborConfig *BgpIfmapInstanceConfig::FindNeighbor(
    const string &name) const {
    NeighborMap::const_iterator loc;

    if (name.find(name_) == string::npos) {
        string fqn(name_);
        fqn += ":";
        fqn += name;
        loc = neighbors_.find(fqn);
    } else {
        loc = neighbors_.find(name);
    }

    return loc != neighbors_.end() ? loc->second : NULL;
}

//
// Add a BgpPeeringConfig to this BgpIfmapInstanceConfig.
//
void BgpIfmapInstanceConfig::AddPeering(BgpIfmapPeeringConfig *peering) {
    peerings_.insert(make_pair(peering->name(), peering));
}

//
// Delete a BgpPeeringConfig from this BgpIfmapInstanceConfig.
//
void BgpIfmapInstanceConfig::DeletePeering(BgpIfmapPeeringConfig *peering) {
    peerings_.erase(peering->name());
}

//
// Add a BgpIfmapRoutingPolicyConfig to this BgpIfmapInstanceConfig.
//
void BgpIfmapInstanceConfig::AddRoutingPolicy(
    BgpIfmapRoutingPolicyConfig *rtp) {
    routing_policies_.insert(make_pair(rtp->name(), rtp));
}

//
// Delete a BgpIfmapRoutingPolicyConfig from this BgpIfmapInstanceConfig.
//
void BgpIfmapInstanceConfig::DeleteRoutingPolicy(
    BgpIfmapRoutingPolicyConfig *rtp) {
    routing_policies_.erase(rtp->name());
}

//
// Constructor for BgpIfmapConfigData.
//
BgpIfmapConfigData::BgpIfmapConfigData() {
}

//
// Destructor for BgpConfigData.
//
BgpIfmapConfigData::~BgpIfmapConfigData() {
    STLDeleteElements(&instances_);
    STLDeleteElements(&peerings_);
    STLDeleteElements(&routing_policies_);
    STLDeleteElements(&ri_rp_links_);
}

//
// Locate the BgpIfmapInstanceConfig by name, create it if not found.  The newly
// created BgpIfmapInstanceConfig gets added to the IfmapInstanceMap.
//
// Note that we do not have the IFMapNode representing the routing-instance
// at this point.
//
BgpIfmapInstanceConfig *BgpIfmapConfigData::LocateInstance(const string &name) {
    BgpIfmapInstanceConfig *rti = FindInstance(name);
    if (rti != NULL) {
        return rti;
    }
    rti = new BgpIfmapInstanceConfig(name);
    pair<IfmapInstanceMap::iterator, bool> result =
            instances_.insert(make_pair(name, rti));
    assert(result.second);
    pair<BgpInstanceMap::iterator, bool> result2 =
            instance_config_map_.insert(
                make_pair(name, rti->instance_config()));
    assert(result2.second);
    return rti;
}

//
// Remove the given BgpIfmapInstanceConfig from the IfmapInstanceMap
// and delete it.
//
void BgpIfmapConfigData::DeleteInstance(BgpIfmapInstanceConfig *rti) {
    IfmapInstanceMap::iterator loc = instances_.find(rti->name());
    assert(loc != instances_.end());
    instances_.erase(loc);
    BgpInstanceMap::iterator loc2 = instance_config_map_.find(rti->name());
    assert(loc2 != instance_config_map_.end());
    instance_config_map_.erase(loc2);
    delete rti;
}

//
// Find the BgpIfmapInstanceConfig by name.
//
BgpIfmapInstanceConfig *BgpIfmapConfigData::FindInstance(const string &name) {
    IfmapInstanceMap::iterator loc = instances_.find(name);
    if (loc != instances_.end()) {
        return loc->second;
    }
    return NULL;
}

//
// Find the BgpIfmapInstanceConfig by name.
// Const version.
//
const BgpIfmapInstanceConfig *BgpIfmapConfigData::FindInstance(
    const string &name) const {
    IfmapInstanceMap::const_iterator loc = instances_.find(name);
    if (loc != instances_.end()) {
        return loc->second;
    }
    return NULL;
}

BgpConfigManager::NeighborMapRange
BgpIfmapInstanceConfig::NeighborMapItems() const {
    return make_pair(neighbors_.begin(), neighbors_.end());
}

//
// Create a new BgpIfmapRoutingPolicyLinkConfig.
//
// The IFMapNodeProxy is a proxy for the IFMapNode which is the midnode that
// represents the routing-policy-routing-instance. The newly created
// BgpIfmapRoutingPolicyLinkConfig gets added to the IfmapRoutingPolicyLinkMap.
//
BgpIfmapRoutingPolicyLinkConfig *BgpIfmapConfigData::CreateRoutingPolicyLink(
    BgpIfmapInstanceConfig *rti, BgpIfmapRoutingPolicyConfig *rtp,
    IFMapNodeProxy *proxy) {
    BgpIfmapRoutingPolicyLinkConfig *ri_rp_link =
        new BgpIfmapRoutingPolicyLinkConfig(rti, rtp);
    ri_rp_link->SetNodeProxy(proxy);
    pair<IfmapRoutingPolicyLinkMap::iterator, bool> result =
        ri_rp_links_.insert(make_pair(ri_rp_link->node()->name(), ri_rp_link));
    assert(result.second);
    ri_rp_link->instance()->AddRoutingPolicy(rtp);
    ri_rp_link->policy()->AddInstance(rti);
    return ri_rp_link;
}

//
// Delete a BgpIfmapRoutingPolicyLinkConfig.
//
// The BgpIfmapRoutingPolicyLinkConfig is erased from IfmapRoutingPolicyLinkMap
// and then deleted.
// Note that the reference to the IFMapNode for routing-policy-routing-instance
// gets released via the destructor when the IFMapNodeProxy is destroyed.
//
void BgpIfmapConfigData::DeleteRoutingPolicyLink(
    BgpIfmapRoutingPolicyLinkConfig *ri_rp_link) {
    ri_rp_links_.erase(ri_rp_link->node()->name());
    ri_rp_link->instance()->DeleteRoutingPolicy(ri_rp_link->policy());
    ri_rp_link->policy()->RemoveInstance(ri_rp_link->instance());
    delete ri_rp_link;
}

//
// Find the BgpIfmapRoutingPolicyLinkConfig by name.
//
BgpIfmapRoutingPolicyLinkConfig *BgpIfmapConfigData::FindRoutingPolicyLink(
    const string &name) {
    IfmapRoutingPolicyLinkMap::iterator loc = ri_rp_links_.find(name);
    if (loc != ri_rp_links_.end()) {
        return loc->second;
    }
    return NULL;
}

//
// Find the BgpIfmapRoutingPolicyLinkConfig by name.
// Const version.
//
const BgpIfmapRoutingPolicyLinkConfig *
BgpIfmapConfigData::FindRoutingPolicyLink(const string &name) const {
    IfmapRoutingPolicyLinkMap::const_iterator loc = ri_rp_links_.find(name);
    if (loc != ri_rp_links_.end()) {
        return loc->second;
    }
    return NULL;
}

//
// Create a new BgpIfmapPeeringConfig.
//
// The IFMapNodeProxy is a proxy for the IFMapNode which is the
// midnode that represents the bgp-peering. The newly created
// BgpIfmapPeeringConfig gets added to the IfmapPeeringMap.
//
BgpIfmapPeeringConfig *BgpIfmapConfigData::CreatePeering(
    BgpIfmapInstanceConfig *rti, IFMapNodeProxy *proxy) {
    BgpIfmapPeeringConfig *peering = new BgpIfmapPeeringConfig(rti);
    peering->SetNodeProxy(proxy);
    pair<IfmapPeeringMap::iterator, bool> result =
            peerings_.insert(make_pair(peering->node()->name(), peering));
    assert(result.second);
    peering->instance()->AddPeering(peering);
    return peering;
}

//
// Delete a BgpPeeringConfig.
//
// The BgpPeeringConfig is removed from the IfmapPeeringMap and then deleted.
// Note that the reference to the IFMapNode for the bgp-peering gets released
// via the destructor when the IFMapNodeProxy is destroyed.
//
void BgpIfmapConfigData::DeletePeering(BgpIfmapPeeringConfig *peering) {
    peering->instance()->DeletePeering(peering);
    peerings_.erase(peering->node()->name());
    delete peering;
}

//
// Find the BgpPeeringConfig by name.
//
BgpIfmapPeeringConfig *BgpIfmapConfigData::FindPeering(const string &name) {
    IfmapPeeringMap::iterator loc = peerings_.find(name);
    if (loc != peerings_.end()) {
        return loc->second;
    }
    return NULL;
}

//
// Find the BgpPeeringConfig by name.
// Const version.
//
const BgpIfmapPeeringConfig *BgpIfmapConfigData::FindPeering(
    const string &name) const {
    IfmapPeeringMap::const_iterator loc = peerings_.find(name);
    if (loc != peerings_.end()) {
        return loc->second;
    }
    return NULL;
}

BgpConfigManager::InstanceMapRange
BgpIfmapConfigData::InstanceMapItems(const string &start_name) const {
    return make_pair(instance_config_map_.lower_bound(start_name),
        instance_config_map_.end());
}

BgpConfigManager::RoutingPolicyMapRange
BgpIfmapConfigData::RoutingPolicyMapItems(const string &start_name) const {
    return make_pair(routing_policy_config_map_.lower_bound(start_name),
        routing_policy_config_map_.end());
}

//
// Locate the BgpIfmapRoutingPolicyConfig by name, create it if not found.
// The newly created BgpIfmapRoutingPolicyConfig gets added to the
// IfmapRoutingPolicyMap.
//
BgpIfmapRoutingPolicyConfig *BgpIfmapConfigData::LocateRoutingPolicy(
    const string &name) {
    BgpIfmapRoutingPolicyConfig *rtp = FindRoutingPolicy(name);
    if (rtp != NULL) {
        return rtp;
    }
    rtp = new BgpIfmapRoutingPolicyConfig(name);
    pair<IfmapRoutingPolicyMap::iterator, bool> result =
            routing_policies_.insert(make_pair(name, rtp));
    assert(result.second);
    pair<BgpRoutingPolicyMap::iterator, bool> result2 =
            routing_policy_config_map_.insert(
                make_pair(name, rtp->routing_policy_config()));
    assert(result2.second);
    return rtp;
}

//
// Remove the given BgpIfmapRoutingPolicyConfig from the IfmapRoutingPolicyMap
// and delete it.
//
void BgpIfmapConfigData::DeleteRoutingPolicy(BgpIfmapRoutingPolicyConfig *rtp) {
    IfmapRoutingPolicyMap::iterator loc = routing_policies_.find(rtp->name());
    assert(loc != routing_policies_.end());
    routing_policies_.erase(loc);
    BgpRoutingPolicyMap::iterator loc2 =
        routing_policy_config_map_.find(rtp->name());
    assert(loc2 != routing_policy_config_map_.end());
    routing_policy_config_map_.erase(loc2);
    delete rtp;
}

BgpIfmapRoutingPolicyConfig *BgpIfmapConfigData::FindRoutingPolicy(
    const string &name) {
    IfmapRoutingPolicyMap::iterator loc = routing_policies_.find(name);
    if (loc != routing_policies_.end()) {
        return loc->second;
    }
    return NULL;
}

const BgpIfmapRoutingPolicyConfig *BgpIfmapConfigData::FindRoutingPolicy(
    const string &name) const {
    IfmapRoutingPolicyMap::const_iterator loc = routing_policies_.find(name);
    if (loc != routing_policies_.end()) {
        return loc->second;
    }
    return NULL;
}

//
// Constructor for BgpIfmapConfigManager.
//
BgpIfmapConfigManager::BgpIfmapConfigManager(BgpServer *server)
    : BgpConfigManager(server),
      db_(NULL),
      db_graph_(NULL),
      trigger_(boost::bind(&BgpIfmapConfigManager::ConfigHandler, this),
          TaskScheduler::GetInstance()->GetTaskId("bgp::Config"),
          kConfigTaskInstanceId),
      listener_(new BgpConfigListener(this)),
      config_(new BgpIfmapConfigData()) {
    IdentifierMapInit();
}

//
// Destructor for BgpIfmapConfigManager.
//
BgpIfmapConfigManager::~BgpIfmapConfigManager() {
}

//
// Initialize the BgpConfigManager.
//
void BgpIfmapConfigManager::Initialize(DB *db, DBGraph *db_graph,
                                       const string &localname) {
    db_ = db;
    db_graph_ = db_graph;
    localname_ = localname;
    listener_->Initialize();
    DefaultConfig();
}

//
// Used to trigger a build and subsequent evaluation of the ChangeList.
//
void BgpIfmapConfigManager::OnChange() {
    CHECK_CONCURRENCY("db::IFMapTable");
    trigger_.Set();
}

BgpConfigManager::InstanceMapRange
BgpIfmapConfigManager::InstanceMapItems(const string &start_name) const {
    return config_->InstanceMapItems(start_name);
}

BgpConfigManager::RoutingPolicyMapRange
BgpIfmapConfigManager::RoutingPolicyMapItems(const string &start_name) const {
    return config_->RoutingPolicyMapItems(start_name);
}

BgpConfigManager::NeighborMapRange
BgpIfmapConfigManager::NeighborMapItems(
    const string &instance_name) const {
    static BgpConfigManager::NeighborMap nilMap;
    BgpIfmapInstanceConfig *rti = config_->FindInstance(instance_name);
    if (rti == NULL) {
        return make_pair(nilMap.begin(), nilMap.end());
    }
    return rti->NeighborMapItems();
}

int BgpIfmapConfigManager::NeighborCount(
    const string &instance_name) const {
    BgpIfmapInstanceConfig *rti = config_->FindInstance(instance_name);
    if (rti == NULL) {
        return 0;
    }
    return rti->neighbors().size();
}

//
// Constructor for BgpIfmapRoutingPolicyConfig.
//
BgpIfmapRoutingPolicyConfig::BgpIfmapRoutingPolicyConfig(
    const string &name)
    : name_(name),
      data_(name) {
}

//
// Destructor for BgpIfmapRoutingPolicyConfig.
//
BgpIfmapRoutingPolicyConfig::~BgpIfmapRoutingPolicyConfig() {
}

//
// Set the IFMapNodeProxy for the BgpIfmapRoutingPolicyConfig.
//
void BgpIfmapRoutingPolicyConfig::SetNodeProxy(IFMapNodeProxy *proxy) {
    if (proxy != NULL) {
        node_proxy_.Swap(proxy);
    }
}

void BgpIfmapRoutingPolicyConfig::Delete(BgpConfigManager *manager) {
    manager->Notify(&data_, BgpConfigManager::CFG_DELETE);
    routing_policy_.reset();
}

//
// Return true if the BgpIfmapRoutingPolicyConfig is ready to be deleted.
// The caller is responsible for actually deleting it.
//
bool BgpIfmapRoutingPolicyConfig::DeleteIfEmpty(BgpConfigManager *manager) {
    if (node() != NULL) {
        return false;
    }
    if (!instances_.empty()) {
        return false;
    }

    Delete(manager);
    return true;
}

//
// Add a BgpIfmapInstanceConfig to BgpIfmapRoutingPolicyConfig.
//
void BgpIfmapRoutingPolicyConfig::AddInstance(BgpIfmapInstanceConfig *rti) {
    instances_.insert(make_pair(rti->name(), rti));
}

//
// Remove a BgpIfmapInstanceConfig to BgpIfmapRoutingPolicyConfig.
//
void BgpIfmapRoutingPolicyConfig::RemoveInstance(BgpIfmapInstanceConfig *rti) {
    instances_.erase(rti->name());
}

static void BuildPolicyTerm(autogen::PolicyTermType cfg_term,
    RoutingPolicyTerm *term) {
    term->match.protocols_match = cfg_term.term_match_condition.protocol;
    term->match.community_match = cfg_term.term_match_condition.community;
    BOOST_FOREACH(const autogen::PrefixMatchType &prefix_match,
                  cfg_term.term_match_condition.prefix) {
        PrefixMatchConfig match;
        match.prefix_to_match = prefix_match.prefix;
        match.prefix_match_type = prefix_match.prefix_type.empty() ?
            "exact" : prefix_match.prefix_type;
        term->match.prefixes_to_match.push_back(match);
    }

    BOOST_FOREACH(const string community,
                  cfg_term.term_action_list.update.community.add.community) {
        term->action.update.community_add.push_back(community);
    }
    BOOST_FOREACH(const string community,
                  cfg_term.term_action_list.update.community.remove.community) {
        term->action.update.community_remove.push_back(community);
    }
    BOOST_FOREACH(const string community,
                  cfg_term.term_action_list.update.community.set.community) {
        term->action.update.community_set.push_back(community);
    }
    term->action.update.local_pref =
        cfg_term.term_action_list.update.local_pref;
    term->action.update.med = cfg_term.term_action_list.update.med;
    term->action.action = RoutingPolicyActionConfig::NEXT_TERM;
    if (strcmp(cfg_term.term_action_list.action.c_str(), "reject") == 0)
        term->action.action = RoutingPolicyActionConfig::REJECT;
    else if (strcmp(cfg_term.term_action_list.action.c_str(), "accept") == 0)
        term->action.action = RoutingPolicyActionConfig::ACCEPT;
}

static void BuildPolicyTerms(BgpRoutingPolicyConfig *policy_cfg,
    const autogen::RoutingPolicy *policy) {
    vector<autogen::PolicyTermType> terms = policy->entries();
    BOOST_FOREACH(autogen::PolicyTermType cfg_term, terms) {
        RoutingPolicyTerm policy_term;
        BuildPolicyTerm(cfg_term, &policy_term);
        policy_cfg->add_term(policy_term);
    }
}

void BgpIfmapRoutingPolicyConfig::Update(BgpIfmapConfigManager *manager,
    const autogen::RoutingPolicy *policy) {
    routing_policy_.reset(policy);
    data_.Clear();
    if (policy) {
        BuildPolicyTerms(&data_, policy);
    }
}

//
// Reset IFMap related state in the BgpIfmapRoutingPolicyConfig.
//
void BgpIfmapRoutingPolicyConfig::ResetConfig() {
    node_proxy_.Clear();
}

const BgpRoutingPolicyConfig *BgpIfmapConfigManager::FindRoutingPolicy(
    const string &name) const {
    BgpIfmapRoutingPolicyConfig *rtp = config_->FindRoutingPolicy(name);
    if (rtp == NULL) {
        return NULL;
    }
    return rtp->routing_policy_config();
}

const BgpInstanceConfig *BgpIfmapConfigManager::FindInstance(
    const string &name) const {
    BgpIfmapInstanceConfig *rti = config_->FindInstance(name);
    if (rti == NULL) {
        return NULL;
    }
    return rti->instance_config();
}

const BgpProtocolConfig *BgpIfmapConfigManager::GetProtocolConfig(
    const string &instance_name) const {
    BgpIfmapInstanceConfig *rti = config_->FindInstance(instance_name);
    if (rti == NULL) {
        return NULL;
    }
    const BgpIfmapProtocolConfig *proto = rti->protocol_config();
    if (proto == NULL) {
        return NULL;
    }
    return proto->protocol_config();
}

const BgpNeighborConfig *BgpIfmapConfigManager::FindNeighbor(
    const string &instance_name, const string &name) const {
    BgpIfmapInstanceConfig *rti = config_->FindInstance(instance_name);
    if (rti == NULL) {
        return NULL;
    }
    return rti->FindNeighbor(name);
}

//
// Initialize autogen::BgpRouterParams with default values.
//
void BgpIfmapConfigManager::DefaultBgpRouterParams(
    autogen::BgpRouterParams *param) {
    param->Clear();
    param->autonomous_system = BgpConfigManager::kDefaultAutonomousSystem;
    param->port = BgpConfigManager::kDefaultPort;
}

//
// Create BgpInsatnceConfig for master routing-instance.  This
// includes the BgpIfmapProtocolConfig for the local bgp-router in the
// master routing-instance.
//
void BgpIfmapConfigManager::DefaultConfig() {
    BgpIfmapInstanceConfig *rti = config_->LocateInstance(kMasterInstance);
    auto_ptr<autogen::BgpRouter> router(new autogen::BgpRouter());
    autogen::BgpRouterParams param;
    DefaultBgpRouterParams(&param);
    router->SetProperty("bgp-router-parameters", &param);
    BgpIfmapProtocolConfig *protocol = rti->LocateProtocol();
    protocol->Update(this, router.release());
    Notify(rti->instance_config(), BgpConfigManager::CFG_ADD);

    vector<string> import_list;
    vector<string> export_list;
    BGP_CONFIG_LOG_INSTANCE(
        Create, server(), rti, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
        import_list, export_list,
        rti->virtual_network(), rti->virtual_network_index());

    BGP_CONFIG_LOG_PROTOCOL(
        Create, server(), protocol,
        SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
        protocol->router_params().admin_down,
        protocol->router_params().autonomous_system,
        protocol->router_params().identifier,
        protocol->router_params().address,
        protocol->router_params().hold_time,
        vector<string>());
}

bool BgpIfmapGlobalSystemConfig::Update(BgpIfmapConfigManager *manager,
        const autogen::GlobalSystemConfig *system) {
    bool changed = false;

    if (data_.gr_enable() != system->graceful_restart_parameters().enable) {
        data_.set_gr_enable(system->graceful_restart_parameters().enable);
        changed |= true;
    }

    if (data_.gr_time() != system->graceful_restart_parameters().restart_time) {
        data_.set_gr_time(system->graceful_restart_parameters().restart_time);
        changed |= true;
    }

    if (data_.llgr_time() != static_cast<uint32_t>(
            system->graceful_restart_parameters().long_lived_restart_time)) {
        data_.set_llgr_time(
            system->graceful_restart_parameters().long_lived_restart_time);
        changed |= true;
    }

    if (data_.end_of_rib_timeout() !=
            system->graceful_restart_parameters().end_of_rib_timeout) {
        data_.set_end_of_rib_timeout(
            system->graceful_restart_parameters().end_of_rib_timeout);
        changed |= true;
    }

    if (data_.gr_bgp_helper() !=
            system->graceful_restart_parameters().bgp_helper_enable) {
        data_.set_gr_bgp_helper(
            system->graceful_restart_parameters().bgp_helper_enable);
        changed |= true;
    }

    if (data_.gr_xmpp_helper() !=
            system->graceful_restart_parameters().xmpp_helper_enable) {
        data_.set_gr_xmpp_helper(
            system->graceful_restart_parameters().xmpp_helper_enable);
        changed |= true;
    }

    return changed;
}

//
// Initialize IdentifierMap with handlers for interesting identifier types.
//
// The IdentifierMap is used when processing BgpConfigDeltas generated by
// the BgpConfigListener.
//
void BgpIfmapConfigManager::IdentifierMapInit() {
    id_map_.insert(make_pair("routing-instance",
            boost::bind(&BgpIfmapConfigManager::ProcessRoutingInstance,
                        this, _1)));
    id_map_.insert(make_pair("routing-policy",
        boost::bind(&BgpIfmapConfigManager::ProcessRoutingPolicy, this, _1)));
    id_map_.insert(make_pair("routing-policy-routing-instance",
        boost::bind(&BgpIfmapConfigManager::ProcessRoutingPolicyLink, this,
            _1)));
    id_map_.insert(make_pair("bgp-router",
        boost::bind(&BgpIfmapConfigManager::ProcessBgpRouter, this, _1)));
    id_map_.insert(make_pair("bgp-peering",
        boost::bind(&BgpIfmapConfigManager::ProcessBgpPeering, this, _1)));
    id_map_.insert(make_pair("global-system-config",
        boost::bind(&BgpIfmapConfigManager::ProcessGlobalSystemConfig, this,
                    _1)));
}

//
// Handler for routing-instance objects.
//
// Note that BgpIfmapInstanceConfig object for the master instance is created
// before we have received any configuration for it i.e. there's no IFMapNode
// or autogen::RoutingInstance for it. However, we will eventually receive a
// delta for the master.  The IFMapNodeProxy and autogen::RoutingInstance are
// set at that time.
//
// For other routing-instances BgpIfmapConfigInstance can get created before we
// see the IFMapNode for the routing-instance if we see the IFMapNode for the
// local bgp-router in the routing-instance.  In this case, the IFMapNodeProxy
// and autogen::RoutingInstance are set when we later see the IFMapNode for the
// routing-instance.
//
// In all other cases, BgpIfmapConfigInstance is created when we see IFMapNode
// for the routing-instance.  The IFMapNodeProxy and autogen::RoutingInstance
// are set right away.
//
// References to the IFMapNode and the autogen::RoutingInstance are
// released when the IFMapNode is marked deleted.  However the
// BgpIfmapInstanceConfig does not get deleted till the NeighborMap is
// empty and the BgpIfmapProtocolConfig is gone.
//
void BgpIfmapConfigManager::ProcessRoutingInstance(
    const BgpConfigDelta &delta) {
    CHECK_CONCURRENCY("bgp::Config");

    BgpConfigManager::EventType event = BgpConfigManager::CFG_CHANGE;
    string instance_name = delta.id_name;
    BgpIfmapInstanceConfig *rti = config_->FindInstance(instance_name);
    if (rti == NULL) {
        IFMapNodeProxy *proxy = delta.node.get();
        if (proxy == NULL) {
            return;
        }
        IFMapNode *node = proxy->node();
        if (node == NULL || node->IsDeleted()) {
            return;
        }
        event = BgpConfigManager::CFG_ADD;
        rti = config_->LocateInstance(instance_name);
        rti->SetNodeProxy(proxy);
    } else {
        IFMapNode *node = rti->node();
        if (node == NULL) {
            IFMapNodeProxy *proxy = delta.node.get();
            if (proxy == NULL) {
                return;
            }
            rti->SetNodeProxy(proxy);
        } else if (node->IsDeleted()) {
            rti->ResetConfig();
            if (rti->DeleteIfEmpty(this)) {
                BGP_CONFIG_LOG_INSTANCE(
                    Delete, server(), rti,
                    SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL);
                config_->DeleteInstance(rti);
            }
            return;
        }
    }

    autogen::RoutingInstance *rti_config =
        static_cast<autogen::RoutingInstance *>(delta.obj.get());
    rti->Update(this, rti_config);
    Notify(rti->instance_config(), event);

    vector<string> import_rt(rti->import_list().begin(),
                             rti->import_list().end());
    vector<string> export_rt(rti->export_list().begin(),
                             rti->export_list().end());
    if (event == BgpConfigManager::CFG_ADD) {
        BGP_CONFIG_LOG_INSTANCE(Create, server(), rti,
            SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
            import_rt, export_rt,
            rti->virtual_network(), rti->virtual_network_index());
    } else {
        BGP_CONFIG_LOG_INSTANCE(Update, server(), rti,
            SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
            import_rt, export_rt,
            rti->virtual_network(), rti->virtual_network_index());
    }
}

//
// Handler for bgp protocol config.
//
// Note that there's no underlying IFMap object for the bgp protocol config.
// This is called by the handler for bgp-router objects. The BgpConfigDelta
// is a delta for the bgp-router object.
//
void BgpIfmapConfigManager::ProcessBgpProtocol(const BgpConfigDelta &delta) {
    CHECK_CONCURRENCY("bgp::Config");

    BgpConfigManager::EventType event = BgpConfigManager::CFG_CHANGE;
    string instance_name(IdentifierParent(delta.id_name));
    BgpIfmapInstanceConfig *rti = config_->FindInstance(instance_name);
    BgpIfmapProtocolConfig *protocol = NULL;
    if (rti != NULL) {
        protocol = rti->protocol_config_mutable();
    }

    if (protocol == NULL) {
        IFMapNodeProxy *proxy = delta.node.get();
        if (proxy == NULL) {
            return;
        }
        // ignore identifier with no properties
        if (delta.obj.get() == NULL) {
            return;
        }
        IFMapNode *node = proxy->node();
        if (node == NULL || node->IsDeleted()) {
            return;
        }
        event = BgpConfigManager::CFG_ADD;
        if (rti == NULL) {
            rti = config_->LocateInstance(instance_name);
            Notify(rti->instance_config(), BgpConfigManager::CFG_ADD);

            vector<string> import_rt(rti->import_list().begin(),
                                     rti->import_list().end());
            vector<string> export_rt(rti->export_list().begin(),
                                     rti->export_list().end());
            BGP_CONFIG_LOG_INSTANCE(Create, server(), rti,
                SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
                import_rt, export_rt,
                rti->virtual_network(), rti->virtual_network_index());
        }
        protocol = rti->LocateProtocol();
        protocol->SetNodeProxy(proxy);
    } else {
        IFMapNode *node = protocol->node();
        if (node == NULL) {
            // The master instance creates a BgpRouter node internally. Ignore
            // an update that doesn't specify any content.
            if (delta.obj.get() == NULL) {
                return;
            }
            protocol->SetNodeProxy(delta.node.get());
        } else if (delta.obj.get() == NULL) {
            BGP_CONFIG_LOG_PROTOCOL(Delete, server(), protocol,
                SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL);
            protocol->Delete(this);
            rti->ResetProtocol();
            if (rti->DeleteIfEmpty(this)) {
                BGP_CONFIG_LOG_INSTANCE(Delete, server(), rti,
                    SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL);
                config_->DeleteInstance(rti);
            }
            return;
        }
    }

    autogen::BgpRouter *rt_config =
        static_cast<autogen::BgpRouter *>(delta.obj.get());
    protocol->Update(this, rt_config);
    Notify(protocol->protocol_config(), event);

    if (!rt_config) {
        return;
    }

    vector<string> families(
        protocol->router_params().address_families.begin(),
        protocol->router_params().address_families.end());
    if (event == BgpConfigManager::CFG_ADD) {
        BGP_CONFIG_LOG_PROTOCOL(Create, server(), protocol,
            SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
            protocol->router_params().admin_down,
            protocol->router_params().autonomous_system,
            protocol->router_params().identifier,
            protocol->router_params().address,
            protocol->router_params().hold_time,
            families);
    } else {
        BGP_CONFIG_LOG_PROTOCOL(Update, server(), protocol,
            SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
            protocol->router_params().admin_down,
            protocol->router_params().autonomous_system,
            protocol->router_params().identifier,
            protocol->router_params().address,
            protocol->router_params().hold_time,
            families);
    }
}

//
// Handler for routing policy objects.
//
// BgpConfigListener::DependencyTracker ensures associated routing instances
// are present in the change list.
//
void BgpIfmapConfigManager::ProcessRoutingPolicy(const BgpConfigDelta &delta) {
    CHECK_CONCURRENCY("bgp::Config");

    BgpConfigManager::EventType event = BgpConfigManager::CFG_CHANGE;
    string policy_name = delta.id_name;
    BgpIfmapRoutingPolicyConfig *rtp = config_->FindRoutingPolicy(policy_name);
    if (rtp == NULL) {
        IFMapNodeProxy *proxy = delta.node.get();
        if (proxy == NULL) {
            return;
        }
        IFMapNode *node = proxy->node();
        if (node == NULL || node->IsDeleted()) {
            return;
        }
        event = BgpConfigManager::CFG_ADD;
        rtp = config_->LocateRoutingPolicy(policy_name);
        rtp->SetNodeProxy(proxy);
    } else {
        IFMapNode *node = rtp->node();
        if (node == NULL) {
            IFMapNodeProxy *proxy = delta.node.get();
            if (proxy == NULL) {
                return;
            }
            rtp->SetNodeProxy(proxy);
        } else if (node->IsDeleted()) {
            rtp->ResetConfig();
            if (rtp->DeleteIfEmpty(this)) {
                config_->DeleteRoutingPolicy(rtp);
            }
            return;
        }
    }

    autogen::RoutingPolicy *rtp_config =
        static_cast<autogen::RoutingPolicy *>(delta.obj.get());
    rtp->Update(this, rtp_config);
    Notify(rtp->routing_policy_config(), event);
}

//
// Handler for bgp-router objects.
//
void BgpIfmapConfigManager::ProcessBgpRouter(const BgpConfigDelta &delta) {
    CHECK_CONCURRENCY("bgp::Config");

    string instance_name(IdentifierParent(delta.id_name));
    if (instance_name.empty() ||
        instance_name != BgpConfigManager::kMasterInstance) {
        return;
    }

    // Ignore if this change is not for the local router.
    string name = delta.id_name.substr(instance_name.size() + 1);
    if (name != localname_) {
        return;
    }

    ProcessBgpProtocol(delta);

    // Update all peerings since we use local asn and identifier from master
    // instance for all neighbors, including those in non-master instances.
    BOOST_FOREACH(const BgpIfmapConfigData::IfmapPeeringMap::value_type &value,
        config_->peerings()) {
        BgpIfmapPeeringConfig *peering = value.second;
        peering->Update(this, peering->bgp_peering());
    }
}

//
// Handler for bgp-peering objects.
//
// We are only interested in this bgp-peering if it is adjacent to the local
// router node.
//
// The BgpPeeringConfig is created the first time we see the bgp-peering.  It
// is updated on subsequent changes and is deleted when the IFMapNode midnode
// for the bgp-peering is deleted.
//
// Note that we are guaranteed that the IFMapNodes for the 2
// bgp-routers for the bgp-peering already exist when we see the
// bgp-peering. IFMap creates the nodes for the bgp-routers before
// creating the midnode. This in turn guarantees that the
// BgpIfmapInstanceConfig for the routing-instance also exists since we
// create the BgpIfmapInstanceConfig before creating the
// BgpIfmapProtocolConfig for a local bgp-router.
//
void BgpIfmapConfigManager::ProcessBgpPeering(const BgpConfigDelta &delta) {
    CHECK_CONCURRENCY("bgp::Config");

    BgpConfigManager::EventType event = BgpConfigManager::CFG_CHANGE;
    BgpIfmapPeeringConfig *peering = config_->FindPeering(delta.id_name);
    if (peering == NULL) {
        IFMapNodeProxy *proxy = delta.node.get();
        if (proxy == NULL) {
            return;
        }
        IFMapNode *node = proxy->node();
        if (node == NULL || delta.obj.get() == NULL) {
            return;
        }

        pair<IFMapNode *, IFMapNode *> routers;
        if (!BgpIfmapPeeringConfig::GetRouterPair(db_graph_, localname_, node,
                                                  &routers)) {
            return;
        }

        event = BgpConfigManager::CFG_ADD;
        string instance_name(IdentifierParent(routers.first->name()));
        BgpIfmapInstanceConfig *rti = config_->FindInstance(instance_name);
        if (rti == NULL) {
            return;
        }
        peering = config_->CreatePeering(rti, proxy);
    } else {
        const IFMapNode *node = peering->node();
        assert(node != NULL);
        if (delta.obj.get() == NULL) {
            BGP_CONFIG_LOG_PEERING(Delete, server(), peering,
                SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL);
            BgpIfmapInstanceConfig *rti = peering->instance();
            peering->Delete(this);
            config_->DeletePeering(peering);
            if (rti->DeleteIfEmpty(this)) {
                BGP_CONFIG_LOG_INSTANCE(Delete, server(), rti,
                    SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL);
                config_->DeleteInstance(rti);
            }
            return;
        }
    }

    if (event == BgpConfigManager::CFG_ADD) {
        BGP_CONFIG_LOG_PEERING(Create, server(), peering,
            SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL);
    } else {
        BGP_CONFIG_LOG_PEERING(Update, server(), peering,
            SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL);
    }
    autogen::BgpPeering *peering_config =
            static_cast<autogen::BgpPeering *>(delta.obj.get());
    peering->Update(this, peering_config);
}

void BgpIfmapConfigManager::ProcessGlobalSystemConfig(
        const BgpConfigDelta &delta) {
    IFMapNodeProxy *proxy = delta.node.get();
    if (proxy == NULL)
        return;

    IFMapNode *node = proxy->node();
    autogen::GlobalSystemConfig *config, default_config;
    if (node == NULL || node->IsDeleted() || delta.obj.get() == NULL) {
        config = &default_config;
    } else {
        config = static_cast<autogen::GlobalSystemConfig *>(delta.obj.get());
    }

    if (config_->global_config()->Update(this, config))
        Notify(config_->global_config()->config(), BgpConfigManager::CFG_ADD);
}

//
// Process the BgpConfigDeltas on the change list. We simply call the handler
// for each delta based on the object's identifier type.
//
void BgpIfmapConfigManager::ProcessChanges(const ChangeList &change_list) {
    CHECK_CONCURRENCY("bgp::Config");

    for (ChangeList::const_iterator iter = change_list.begin();
         iter != change_list.end(); ++iter) {
        IdentifierMap::iterator loc = id_map_.find(iter->id_type);
        if (loc != id_map_.end()) {
            (loc->second)(*iter);
        }
    }
}

//
// Build and process the change list of BgpConfigDeltas.  The logic to build
// the list is in BgpConfigListener and BgpConfigListener::DependencyTracker.
//
bool BgpIfmapConfigManager::ConfigHandler() {
    CHECK_CONCURRENCY("bgp::Config");

    BgpConfigListener::ChangeList change_list;
    listener_->GetChangeList(&change_list);
    ProcessChanges(change_list);
    return true;
}

//
// Terminate the BgpConfigManager.
//
void BgpIfmapConfigManager::Terminate() {
    listener_->Terminate();
    config_.reset();
}

ext: cc

max_stars_repo_name: sagarc-contrail/contrail-controller

max_issues_repo_name: sagarc-contrail/contrail-controller

max_forks_repo_name: sagarc-contrail/contrail-controller


text:
#include <gtest/gtest.h>

#include <Eigen/Core>
#include <Eigen/Geometry>
#include <vector>

#include "../geometry/Polygon2.hh"
#include "helpers.hh"

using namespace std;
using namespace bold;
using namespace Eigen;

TEST (Polygon2Tests, basics)
{
  Polygon2<int>::PointVector points;
  points.emplace_back(0,0);
  points.emplace_back(0,1);
  points.emplace_back(1,0);

  Polygon2<int> poly(points);

  ASSERT_EQ ( 3, poly.vertexCount() );
  EXPECT_TRUE ( VectorsEqual(Vector2i(0,0), poly[0] ));
  EXPECT_TRUE ( VectorsEqual(Vector2i(0,1), poly[1] ));
  EXPECT_TRUE ( VectorsEqual(Vector2i(1,0), poly[2] ));
}

TEST (Polygon2Tests, int_squareContains)
{
  Polygon2<int>::PointVector points;
  points.emplace_back(0,0);
  points.emplace_back(0,2);
  points.emplace_back(2,2);
  points.emplace_back(2,0);

  Polygon2<int> poly(points);

  EXPECT_TRUE( poly.contains(Vector2i(0,0)) );
  EXPECT_TRUE( poly.contains(Vector2i(0,1)) );
  EXPECT_TRUE( poly.contains(Vector2i(1,1)) );

  EXPECT_FALSE( poly.contains(Vector2i(2,1)) );
  EXPECT_FALSE( poly.contains(Vector2i(2,2)) );
  EXPECT_FALSE( poly.contains(Vector2i(3,2)) );
  EXPECT_FALSE( poly.contains(Vector2i(3,3)) );
  EXPECT_FALSE( poly.contains(Vector2i(2,3)) );
  EXPECT_FALSE( poly.contains(Vector2i(0,3)) );
  EXPECT_FALSE( poly.contains(Vector2i(3,0)) );
  EXPECT_FALSE( poly.contains(Vector2i(-1,-1)) );
  EXPECT_FALSE( poly.contains(Vector2i(-1,1)) );
  EXPECT_FALSE( poly.contains(Vector2i(1,-1)) );
}

TEST (Polygon2Tests, float_squareContains)
{
  Polygon2<float>::PointVector points;
  points.emplace_back(0,0);
  points.emplace_back(0,2);
  points.emplace_back(2,2);
  points.emplace_back(2,0);

  Polygon2<float> poly(points);

  EXPECT_TRUE( poly.contains(Vector2f(0,0)) );
  EXPECT_TRUE( poly.contains(Vector2f(0,1)) );
  EXPECT_TRUE( poly.contains(Vector2f(1,1)) );
  EXPECT_TRUE( poly.contains(Vector2f(1.99999,1)) );
  EXPECT_TRUE( poly.contains(Vector2f(1.99999,1.99999)) );

  EXPECT_FALSE( poly.contains(Vector2f(2,1)) );
  EXPECT_FALSE( poly.contains(Vector2f(2,2)) );
  EXPECT_FALSE( poly.contains(Vector2f(3,2)) );
  EXPECT_FALSE( poly.contains(Vector2f(3,3)) );
  EXPECT_FALSE( poly.contains(Vector2f(2,3)) );
  EXPECT_FALSE( poly.contains(Vector2f(0,3)) );
  EXPECT_FALSE( poly.contains(Vector2f(3,0)) );
  EXPECT_FALSE( poly.contains(Vector2f(-1,-1)) );
  EXPECT_FALSE( poly.contains(Vector2f(-1,1)) );
  EXPECT_FALSE( poly.contains(Vector2f(1,-1)) );
}

TEST (Polygon2Tests, double_diamondContains)
{
  Polygon2<double>::PointVector points;
  points.emplace_back(0,0);
  points.emplace_back(-1,1);
  points.emplace_back(0,2);
  points.emplace_back(1,1);

  Polygon2<double> poly(points);

  // vertices
  EXPECT_TRUE( poly.contains(Vector2d(-1,1)) );
  EXPECT_FALSE( poly.contains(Vector2d(0,0)) );
  EXPECT_FALSE( poly.contains(Vector2d(1,1)) );
  EXPECT_FALSE( poly.contains(Vector2d(0,2)) );

  // clearly inside
  EXPECT_TRUE( poly.contains(Vector2d(0,1)) );
  EXPECT_TRUE( poly.contains(Vector2d(0,0.001)) );

  // clearly outside
  EXPECT_FALSE( poly.contains(Vector2d(1,0)) );
  EXPECT_FALSE( poly.contains(Vector2d(1,1)) );
}

TEST (Polygon2Tests, double_triangleContains)
{
  Polygon2<double>::PointVector points;
  points.emplace_back(0,0);
  points.emplace_back(1,0);
  points.emplace_back(0,1);

  Polygon2<double> poly(points);

  EXPECT_TRUE( poly.contains(Vector2d(0,0)) );
  EXPECT_TRUE( poly.contains(Vector2d(0.0001,0.0001)) );
  EXPECT_TRUE( poly.contains(Vector2d(0.0005,0.9990)) );
  EXPECT_TRUE( poly.contains(Vector2d(0.9990,0.0005)) );
  EXPECT_TRUE( poly.contains(Vector2d(0.4999,0.4999)) );

  EXPECT_FALSE( poly.contains(Vector2d(0.0005,1)) );
  EXPECT_FALSE( poly.contains(Vector2d(1,0.0005)) );
  EXPECT_FALSE( poly.contains(Vector2d(0.5001,0.5001)) );
  EXPECT_FALSE( poly.contains(Vector2d(1,1)) );
  EXPECT_FALSE( poly.contains(Vector2d(-0.0001,-0.0001)) );
  EXPECT_FALSE( poly.contains(Vector2d(-0.0001,0.0001)) );
  EXPECT_FALSE( poly.contains(Vector2d(0.0001,-0.0001)) );
}

TEST (Polygon2Tests, clip)
{
  // unit square
  Polygon2<double>::PointVector points;
  points.emplace_back(0,0);
  points.emplace_back(1,0);
  points.emplace_back(1,1);
  points.emplace_back(0,1);

  Polygon2<double> poly(points);

  // Exactly corner to corner, diagonally (touching all four line segments)
  auto clipped = poly.clipLine(LineSegment2d(Vector2d(0,0),Vector2d(1,1)));
  ASSERT_TRUE(clipped.hasValue());
  ASSERT_TRUE(LinesEqual(
    LineSegment2d(Vector2d(0,0),Vector2d(1,1)),
    clipped.value()
  ));

  // Inside, completely contained
  clipped = poly.clipLine(LineSegment2d(Vector2d(0.25,0.25),Vector2d(0.75,0.75)));
  ASSERT_TRUE(clipped.hasValue());
  ASSERT_TRUE(LinesEqual(
    LineSegment2d(Vector2d(0.25,0.25),Vector2d(0.75,0.75)),
    clipped.value()
  ));

  // From inside (corner) to outside, running through diagonally opposite corner (touching all four line segments)
  clipped = poly.clipLine(LineSegment2d(Vector2d(0,0),Vector2d(5,5)));
  ASSERT_TRUE(clipped.hasValue());
  ASSERT_TRUE(LinesEqual(
    LineSegment2d(Vector2d(0,0),Vector2d(1,1)),
    clipped.value()
  ));

  // Completely inside to outside, touching one line segment
  clipped = poly.clipLine(LineSegment2d(Vector2d(0.5,0.5),Vector2d(1.5,0.5)));
  ASSERT_TRUE(clipped.hasValue());
  ASSERT_TRUE(LinesEqual(
    LineSegment2d(Vector2d(0.5,0.5),Vector2d(1,0.5)),
    clipped.value()
  ));

  // Run horizontally through cube, intersecting both left and right edges
  clipped = poly.clipLine(LineSegment2d(Vector2d(-1,0.5),Vector2d(2,0.5)));
  ASSERT_TRUE(clipped.hasValue());
  ASSERT_TRUE(LinesEqual(
    LineSegment2d(Vector2d(0,0.5),Vector2d(1,0.5)),
    clipped.value()
  ));

  // Run diagonally through cube, bisecting the top left quadrant
  clipped = poly.clipLine(LineSegment2d(Vector2d(-0.5,0),Vector2d(1,1.5)));
  ASSERT_TRUE(clipped.hasValue());
  ASSERT_TRUE(LinesEqual(
    LineSegment2d(Vector2d(0,0.5),Vector2d(0.5,1)),
    clipped.value()
  ));
}

max_stars_repo_name: drewnoakes/bold-humanoid

max_issues_repo_name: drewnoakes/bold-humanoid

max_forks_repo_name: drewnoakes/bold-humanoid


text:
#include <Eigen/Dense>
#include <iostream>

using namespace Eigen;
using namespace std;

int main(int, char**)
{
  cout.precision(3);
  MatrixXcf A = MatrixXcf::Random(4,4);
cout << "Here is a random 4x4 matrix, A:" << endl << A << endl << endl;
ComplexSchur<MatrixXcf> schurOfA(A, false); // false means do not compute U
cout << "The triangular matrix T is:" << endl << schurOfA.matrixT() << endl;

  return 0;
}

ext: cpp

max_issues_repo_name: TANHAIYU/planecalib

max_forks_repo_name: TANHAIYU/planecalib