diff --git a/models/yang/annotations/openconfig-mclag-annot.yang b/models/yang/annotations/openconfig-mclag-annot.yang new file mode 100644 index 000000000..789745123 --- /dev/null +++ b/models/yang/annotations/openconfig-mclag-annot.yang @@ -0,0 +1,152 @@ +module openconfig-mclag-annot { + yang-version "1"; + + namespace "http://openconfig.net/yang/mclag-annot"; + prefix "oc-mclag-annot"; + + import sonic-extensions { prefix sonic-ext; } + import openconfig-mclag { prefix oc-mclag; } + + // meta + organization + "SONiC"; + + contact + "SONiC"; + + description + "SONIC VLAN"; + + revision 2020-01-20 { + description + "Initial revision."; + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain { + deviate add { + sonic-ext:table-name "MCLAG_DOMAIN"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:interfaces/oc-mclag:interface { + deviate add { + sonic-ext:table-name "MCLAG_INTERFACE"; + sonic-ext:subtree-transformer "mclag_interface_subtree_xfmr"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:vlan-interfaces/oc-mclag:vlan-interface { + deviate add { + sonic-ext:table-name "MCLAG_UNIQUE_IP"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:config/oc-mclag:domain-id { + deviate add { + sonic-ext:field-name "domain_id"; + sonic-ext:field-transformer "mclag_domainid_fld_xfmr"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:config/oc-mclag:source-address { + deviate add { + sonic-ext:field-name "source_ip"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:config/oc-mclag:peer-address { + deviate add { + sonic-ext:field-name "peer_ip"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:config/oc-mclag:peer-link { + deviate add { + sonic-ext:field-name "peer_link"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:config/oc-mclag:keepalive-interval { + deviate add { + sonic-ext:field-name "keepalive_interval"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:config/oc-mclag:session-timeout { + deviate add { + sonic-ext:field-name "session_timeout"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:state/oc-mclag:domain-id { + deviate add { + sonic-ext:field-name "domain_id"; + sonic-ext:field-transformer "mclag_domainid_fld_xfmr"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:state/oc-mclag:source-address { + deviate add { + sonic-ext:field-name "source_ip"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:state/oc-mclag:peer-address { + deviate add { + sonic-ext:field-name "peer_ip"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:state/oc-mclag:peer-link { + deviate add { + sonic-ext:field-name "peer_link"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:state/oc-mclag:keepalive-interval { + deviate add { + sonic-ext:field-name "keepalive_interval"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:state/oc-mclag:session-timeout { + deviate add { + sonic-ext:field-name "session_timeout"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:state/oc-mclag:oper-status { + deviate add { + sonic-ext:field-transformer "mclag_domain_oper_status_fld_xfmr"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:state/oc-mclag:role { + deviate add { + sonic-ext:field-transformer "mclag_domain_role_fld_xfmr"; + } + } + + + + deviation /oc-mclag:mclag/oc-mclag:vlan-interfaces/oc-mclag:vlan-interface/oc-mclag:config/oc-mclag:unique-ip-enable { + deviate add { + sonic-ext:field-name "unique_ip"; + sonic-ext:field-transformer "mclag_unique_ip_enable_fld_xfmr"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:vlan-interfaces/oc-mclag:vlan-interface/oc-mclag:state/oc-mclag:name { + deviate add { + sonic-ext:field-name "if_name"; + sonic-ext:field-transformer "mclag_vlan_name_fld_xfmr"; + } + } + + deviation /oc-mclag:mclag/oc-mclag:vlan-interfaces/oc-mclag:vlan-interface/oc-mclag:state/oc-mclag:unique-ip-enable { + deviate add { + sonic-ext:field-name "unique_ip"; + sonic-ext:field-transformer "mclag_unique_ip_enable_fld_xfmr"; + } + } +} diff --git a/models/yang/annotations/sonic-mclag-annot.yang b/models/yang/annotations/sonic-mclag-annot.yang new file mode 100644 index 000000000..64a17cf9e --- /dev/null +++ b/models/yang/annotations/sonic-mclag-annot.yang @@ -0,0 +1,38 @@ +module sonic-mclag-annot { + + yang-version "1.1"; + + namespace "http://github.com/Azure/sonic-mclag-annot"; + prefix "smclag-annot"; + + import sonic-extensions { prefix sonic-ext; } + import sonic-mclag { prefix smclag; } + + // meta + organization + "SONiC"; + + contact + "SONiC"; + + description + "SONIC MCLAG"; + + revision 2019-11-22 { + description + "Initial revision."; + } + + deviation /smclag:sonic-mclag/smclag:MCLAG_TABLE/smclag:MCLAG_TABLE_LIST { + deviate add { + sonic-ext:db-name "STATE_DB"; + } + } + + deviation /smclag:sonic-mclag/smclag:MCLAG_REMOTE_INTF_TABLE/smclag:MCLAG_REMOTE_INTF_TABLE_LIST { + deviate add { + sonic-ext:db-name "STATE_DB"; + } + } +} + diff --git a/models/yang/extensions/openconfig-mclag.yang b/models/yang/extensions/openconfig-mclag.yang new file mode 100644 index 000000000..dde2e00f6 --- /dev/null +++ b/models/yang/extensions/openconfig-mclag.yang @@ -0,0 +1,454 @@ +module openconfig-mclag { + + yang-version "1"; + + // namespace + namespace "http://openconfig.net/yang/mclag/extension"; + + prefix "oc-mclag"; + + import openconfig-yang-types { prefix oc-yang; } + import openconfig-inet-types { prefix oc-inet; } + import openconfig-interfaces { prefix oc-if; } + import openconfig-extensions { prefix oc-ext; } + import openconfig-types { prefix oc-types; } + + // meta + organization "OpenConfig working group"; + + contact + "OpenConfig working group + www.openconfig.net"; + + description + "This module defines configuration and operational state data for Multi Chassis LAGs. + MCLAG information are organized as MCLAG Domains.Each MCLAG Domain would contain + config and state inforamtion of domain, it would contain mclag interfaces for that given domain"; + + oc-ext:openconfig-version "1.0.2"; + + revision "2019-12-02" { + description + "Initial revision"; + reference "TBD"; + } + + // OpenConfig specific extensions for module metadata. + oc-ext:regexp-posix; + oc-ext:catalog-organization "openconfig"; + oc-ext:origin "openconfig"; + + typedef mclag-peer-ip-option { + type enumeration { + enum USE_LINK_LOCAL { + description + "Indicates the usage of link-local address to communicate + to MCLAG peer"; + } + } + description + "MCLAG Peer IP options other than configuring peer ip address"; + } + + typedef mclag-peer { + type union { + type oc-inet:ip-address; + type mclag-peer-ip-option; + } + description + "MCLAG peer address can be a configurable IP address or + a link-local address"; + } + + // grouping statements + + grouping mclag-domain-config { + description + "MCLAG Domain config"; + + leaf domain-id { + type uint32 { + range 1..4095; + } + description + "Domain id for MCLAG Domain"; + } + + leaf source-address { + type oc-inet:ip-address; + + description + "source ip address of MCLAG Domain"; + } + + leaf peer-address { + type mclag-peer; + description + "peer address of MCLAG Domain"; + } + + leaf peer-link { + type string; + description + "peer link of MCLAG Domain"; + } + + leaf keepalive-interval { + type uint32 { + range 1..60; + } + default 1; + + description + "Keepalive interval for ICCP MCLAG session"; + } + + leaf session-timeout { + type uint32 { + range 1..3600; + } + default 30; + + description + "Session Timeout for ICCP MCLAG session"; + } + + } + + grouping mclag-domain-state { + description + "MCLAG Domain state"; + + leaf oper-status { + type enumeration { + enum OPER_UP { + description + "MCLAG Session is operationally up"; + } + enum OPER_DOWN { + description + "MCLAG Session is operationally down"; + } + } + description + "MCLAG Domain Session oper status"; + } + + leaf role { + type enumeration { + enum ROLE_ACTIVE { + description + "MCLAG Node Role is Active"; + } + enum ROLE_STANDBY { + description + "MCLAG Node Role is Standby"; + } + } + description + "MCLAG Node's Role"; + } + } + + grouping mclag-domain-top { + description + "MCLAG Domain variables top level container"; + + container mclag-domains { + description + "MCLAG Domain entries variables enclosing container"; + + list mclag-domain { + key "domain-id"; + description + "List of MCLAG Domain entries"; + + leaf domain-id { + type leafref { + path "../config/domain-id"; + } + description + "Reference to the domain-id list key"; + } + + container config { + description + "MCLAG Domain config"; + uses mclag-domain-config; + + } + + container state { + config false; + description + "MCLAG Domain state information"; + uses mclag-domain-config; + uses mclag-domain-state; + } + } + } + } + + + grouping mclag-interface-config { + description + "Configuration data for mclag interfaces"; + + leaf name { + type oc-if:base-interface-ref; + description + "Reference to the MCLAG LAG Interface"; + } + + leaf mclag-domain-id { + type leafref { + path "../../../../mclag-domains/mclag-domain/config/domain-id"; + } + description + "Reference to MCLAG domain list key"; + } + + leaf mclag-id { + type uint16 { + range 1..256; + } + description + "Groups the mclag interfaces among the mclag peers, which + are bundled together to connect to the same attached device. + mclag-id has to be same on all these interfaces."; + } + } + + grouping mclag-interface-state { + description + "Operational state data for local interface references"; + + container local { + description + "Operational state for local interfaces"; + leaf traffic-disable { + type boolean; + default false; + description + "MCLAG local interface traffic disable value to indicate whether Tx/Rx traffic + is disabled or enabled on this MCLAG interface"; + } + + leaf port-isolate { + type boolean; + default false; + description + "MCLAG local interface port isolation state to indicate whether BUM + traffic incoming on ISL is blocked on MCLAG Interface"; + } + + leaf oper-status { + type enumeration { + enum OPER_UP { + description + "Local Interface operational status up"; + } + enum OPER_DOWN { + description + "Local Interface operational status down"; + } + } + default OPER_DOWN; + description + "MCLAG Local Interface Operational status"; + } + } + } + + grouping mclag-remote-interface-state { + description + "Operational state data for remote interface references"; + + container remote { + description + "Operational state data for remote interface references"; + leaf oper-status { + type enumeration { + enum OPER_UP { + description + "Remote Interface operational status up"; + } + enum OPER_DOWN { + description + "Remote Interface operational status down"; + } + } + default OPER_DOWN; + description + "MCLAG Remote Interface Operational status"; + } + } + } + + + grouping mclag-interfaces-top { + description + "Top-level grouping for MCLAG interface-specific data"; + + container interfaces { + description + "Enclosing container for the list of interfaces on which + MCLAG domains are enabled"; + + list interface { + key "name"; + description + "List of interfaces on which MCLAG is configured"; + + leaf name { + type leafref { + path "../config/name"; + } + description + "Reference to the interface id list key"; + } + + container config { + description + "Configuration for MCLAG per-interface data"; + + uses mclag-interface-config; + } + + container state { + + config false; + + description + "Operational state for MCLAG interface data"; + + uses mclag-interface-config; + uses mclag-interface-state; + uses mclag-remote-interface-state; + } + + } + } + } + + grouping mclag-unique-ip-config { + description + "Configuration data for mclag unique ip"; + + leaf name { + type oc-if:base-interface-ref; + description + "Reference to the vlan routed Interface (SVI)"; + } + + leaf unique-ip-enable { + type enumeration { + enum ENABLE { + description + "Enable MCLAG Unique-ip"; + } + } + description + "unique ip enable, default : not enabled"; + } + } + + grouping mclag-unique-ip-top { + description + "Top-level grouping for MCLAG unique-ip specific data"; + + container vlan-interfaces { + description + "Enclosing container for the list of routed vlan + interfaces on which MCLAG unique-ip are enabled"; + + list vlan-interface { + key "name"; + description + "List of interfaces on which MCLAG unique-ip is configured"; + + leaf name { + type leafref { + path "../config/name"; + } + description + "Reference to the interface id list key"; + } + + container config { + description + "Configuration for MCLAG unique-ip per vlan interface data"; + + uses mclag-unique-ip-config; + } + + container state { + + config false; + + description + "Operational state for MCLAG unique-ip per + vlan interface data"; + + uses mclag-unique-ip-config; + } + } + } + } + + grouping mclag-config { + description + "Global configuration data for MCLAG"; + } + + grouping mclag-state { + description + "Global operational state data for MCLAG"; + } + + grouping mclag-top { + description + "Top level grouping for MCLAG data and structure"; + + container mclag { + description + "Top level enclosing container for MCLAG model config + and operational state data"; + + container config { + description + "Global config data for MCLAG"; + uses mclag-config; + } + + container state { + + config false; + + description + "Global operational state data for MCLAG"; + + uses mclag-config; + uses mclag-state; + } + + //mclag domain config and state + uses mclag-domain-top; + uses mclag-interfaces-top; + uses mclag-unique-ip-top; + } + } + + // data definition statements + uses mclag-top; + + // augment statements + + deviation + /oc-mclag:mclag/oc-mclag:mclag-domains/oc-mclag:mclag-domain/oc-mclag:config/oc-mclag:peer-address + { + deviate replace { + type oc-inet:ip-address; + } + } +} diff --git a/models/yang/sonic/sonic-mclag.yang b/models/yang/sonic/sonic-mclag.yang new file mode 100644 index 000000000..dc260f814 --- /dev/null +++ b/models/yang/sonic/sonic-mclag.yang @@ -0,0 +1,242 @@ +module sonic-mclag { + namespace "http://github.com/Azure/sonic-mclag"; + prefix smclag; + yang-version 1.1; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import sonic-common { + prefix scommon; + } + + import sonic-extension { + prefix sonic-ext; + } + + import sonic-port { + prefix prt; + } + + import sonic-portchannel { + prefix spc; + } + + import sonic-vlan { + prefix svlan; + } + + import sonic-vlan-interface { + prefix svlan-intf; + } + + organization + "SONiC"; + + contact + "SONiC"; + + description + "SONIC MCLAG"; + + revision 2019-10-01 { + description + "Initial revision."; + } + + container sonic-mclag { + + container MCLAG_DOMAIN { + + list MCLAG_DOMAIN_LIST { + key "domain_id"; + max-elements 1; + + leaf domain_id { + type uint16 { + range "1..4095" { + error-message "MCLAG Domain ID out of range"; + } + } + } + + leaf source_ip { + type inet:ipv4-address; + } + leaf peer_ip { + type inet:ipv4-address; + } + leaf peer_link { + type union { + type leafref { + path "/prt:sonic-port/prt:PORT/prt:PORT_LIST/prt:ifname"; + } + type leafref { + path "/spc:sonic-portchannel/spc:PORTCHANNEL/spc:PORTCHANNEL_LIST/spc:name"; + } + } + } + leaf keepalive_interval { + type uint16 { + range "1..60" { + error-message "MCLAG Domain keepalive interval out of range"; + error-app-tag keepalive_interval-invalid; + } + } + default 1; + } + leaf session_timeout { + type uint16 { + range "1..3600" { + error-message "MCLAG Domain session timeout out of range"; + error-app-tag session_timeout-invalid; + } + } + default 30; + } + must "(keepalive_interval * 3) <= session_timeout" { + error-message "(keepalive interval * 3) <= session_timeout value"; + error-app-tag keepalive_interval-invalid; + } + } + } + + container MCLAG_INTERFACE { + + list MCLAG_INTERFACE_LIST { + key "domain_id if_name"; + + leaf domain_id { + type leafref { + path "../../../MCLAG_DOMAIN/MCLAG_DOMAIN_LIST/domain_id"; + } + } + + leaf if_name { + type leafref { + path "/spc:sonic-portchannel/spc:PORTCHANNEL/spc:PORTCHANNEL_LIST/spc:name"; + } + } + leaf if_type { + type string; + } + } + } + + container MCLAG_UNIQUE_IP { + + list MCLAG_UNIQUE_IP_LIST { + key "if_name"; + + must "count(../../MCLAG_DOMAIN/MCLAG_DOMAIN_LIST/domain_id) != 0" { + error-message "mclag not configured"; + error-app-tag mclag-invalid; + } + + must "count(/svlan-intf:sonic-vlan-interface/svlan-intf:VLAN_INTERFACE/svlan-intf:VLAN_INTERFACE_IPADDR_LIST[svlan-intf:vlanName=current()/if_name]) = 0" { + error-message "remove configured ip/v6 address and reconfigure after separate ip configuration"; + error-app-tag vlan-intf-ip-invalid; + } + + leaf if_name { + type leafref { + path "/svlan:sonic-vlan/svlan:VLAN/svlan:VLAN_LIST/svlan:name"; + } + } + leaf unique_ip { + type enumeration { + enum enable; + } + } + } + } + + //stateDB MCLAG Table + container MCLAG_TABLE { + sonic-ext:db-name "STATE_DB"; + sonic-ext:key-delim "|"; + + config false; + description "state db mclag domain table"; + + list MCLAG_TABLE_LIST { + key "domain_id"; + + leaf domain_id { + type uint16; + } + + leaf oper_status { + type scommon:oper-status; + } + + leaf role { + type enumeration { + enum active; + enum standby; + } + } + + leaf system_mac { + type yang:mac-address; + description + "System MAC Address used for ICCPD"; + } + } + } + + //state MCLAG Local interface Table + container MCLAG_LOCAL_INTF_TABLE { + + sonic-ext:db-name "STATE_DB"; + sonic-ext:key-delim "|"; + + config false; + description "state db LOCAL interface table"; + + list MCLAG_LOCAL_INTF_TABLE_LIST { + key "if_name"; + + leaf if_name { + type string; + } + + leaf port_isolate_peer_link { + type boolean; + } + } + } + + + //state MCLAG Remote interface Table + container MCLAG_REMOTE_INTF_TABLE { + + sonic-ext:db-name "STATE_DB"; + sonic-ext:key-delim "|"; + + config false; + description "state db remote interface table"; + + list MCLAG_REMOTE_INTF_TABLE_LIST { + key "domain_id if_name"; + + leaf domain_id { + type uint16; + } + + leaf if_name { + type string; + } + + leaf oper_status { + type scommon:oper-status; + } + } + } + } +} diff --git a/translib/transformer/xfmr_mclag.go b/translib/transformer/xfmr_mclag.go new file mode 100644 index 000000000..4567fc82b --- /dev/null +++ b/translib/transformer/xfmr_mclag.go @@ -0,0 +1,266 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright 2019 Dell, Inc. // +// // +// Licensed under the Apache License, Version 2.0 (the "License"); // +// you may not use this file except in compliance with the License. // +// You may obtain a copy of the License at // +// // +// http://www.apache.org/licenses/LICENSE-2.0 // +// // +// Unless required by applicable law or agreed to in writing, software // +// distributed under the License is distributed on an "AS IS" BASIS, // +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // +// See the License for the specific language governing permissions and // +// limitations under the License. // +// // +//////////////////////////////////////////////////////////////////////////////// + +package transformer + +import ( + log "github.com/golang/glog" + "github.com/openconfig/ygot/ygot" + "strconv" + "strings" + "translib/db" + "translib/ocbinds" +) + +func init() { + XlateFuncBind("YangToDb_mclag_domainid_fld_xfmr", YangToDb_mclag_domainid_fld_xfmr) + XlateFuncBind("DbToYang_mclag_domainid_fld_xfmr", DbToYang_mclag_domainid_fld_xfmr) + XlateFuncBind("YangToDb_mclag_vlan_name_fld_xfmr", YangToDb_mclag_vlan_name_fld_xfmr) + XlateFuncBind("DbToYang_mclag_vlan_name_fld_xfmr", DbToYang_mclag_vlan_name_fld_xfmr) + XlateFuncBind("YangToDb_mclag_interface_subtree_xfmr", YangToDb_mclag_interface_subtree_xfmr) + XlateFuncBind("DbToYang_mclag_interface_subtree_xfmr", DbToYang_mclag_interface_subtree_xfmr) + + XlateFuncBind("DbToYang_mclag_domain_oper_status_fld_xfmr", DbToYang_mclag_domain_oper_status_fld_xfmr) + XlateFuncBind("DbToYang_mclag_domain_role_fld_xfmr", DbToYang_mclag_domain_role_fld_xfmr) + XlateFuncBind("DbToYang_mclag_domain_system_mac_fld_xfmr", DbToYang_mclag_domain_system_mac_fld_xfmr) +} + +var YangToDb_mclag_domainid_fld_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[string]string, error) { + res_map := make(map[string]string) + var err error + log.Info("YangToDb_mclag_domainid_fld_xfmr: ", inParams.key) + + return res_map, err +} + +var DbToYang_mclag_domainid_fld_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + log.Info("DbToYang_mclag_domainid_fld_xfmr: ", inParams.key) + result["domain-id"], _ = strconv.ParseUint(inParams.key, 10, 32) + + return result, err +} + +var YangToDb_mclag_vlan_name_fld_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[string]string, error) { + res_map := make(map[string]string) + var err error + log.Info("YangToDb_mclag_vlan_name_fld_xfmr: ", inParams.key) + + return res_map, err +} + +var DbToYang_mclag_vlan_name_fld_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + log.Info("DbToYang_mclag_vlan_name_fld_xfmr: ", inParams.key) + result["name"] = inParams.key + + return result, err +} + +var DbToYang_mclag_domain_oper_status_fld_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + log.Infof("DbToYang_mclag_domain_oper_status_fld_xfmr --> key: %v", inParams.key) + + stDb := inParams.dbs[db.StateDB] + mclagEntry, _ := stDb.GetEntry(&db.TableSpec{Name: "MCLAG_TABLE"}, db.Key{Comp: []string{inParams.key}}) + operStatus := mclagEntry.Get("oper_status") + if operStatus == "up" { + result["oper-status"], _ = ygot.EnumName(ocbinds.OpenconfigMclag_Mclag_MclagDomains_MclagDomain_State_OperStatus_OPER_UP) + } else { + result["oper-status"], _ = ygot.EnumName(ocbinds.OpenconfigMclag_Mclag_MclagDomains_MclagDomain_State_OperStatus_OPER_DOWN) + } + + return result, err +} + +var DbToYang_mclag_domain_role_fld_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + log.Infof("DbToYang_mclag_domain_role_fld_xfmr --> key: %v", inParams.key) + + stDb := inParams.dbs[db.StateDB] + mclagEntry, _ := stDb.GetEntry(&db.TableSpec{Name: "MCLAG_TABLE"}, db.Key{Comp: []string{inParams.key}}) + role := mclagEntry.Get("role") + if role == "active" { + result["role"], _ = ygot.EnumName(ocbinds.OpenconfigMclag_Mclag_MclagDomains_MclagDomain_State_Role_ROLE_ACTIVE) + } else { + result["role"], _ = ygot.EnumName(ocbinds.OpenconfigMclag_Mclag_MclagDomains_MclagDomain_State_Role_ROLE_STANDBY) + } + + return result, err +} + +var DbToYang_mclag_domain_system_mac_fld_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + log.Infof("DbToYang_mclag_domain_system_mac_fld_xfmr --> key: %v", inParams.key) + + stDb := inParams.dbs[db.StateDB] + mclagEntry, _ := stDb.GetEntry(&db.TableSpec{Name: "MCLAG_TABLE"}, db.Key{Comp: []string{inParams.key}}) + sysmac := mclagEntry.Get("system_mac") + result["system-mac"] = &sysmac + + return result, err +} + +var YangToDb_mclag_interface_subtree_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) (map[string]map[string]db.Value, error) { + var err error + res_map := make(map[string]map[string]db.Value) + mclagIntfTblMap := make(map[string]db.Value) + log.Info("YangToDb_mclag_interface_subtree_xfmr: ", inParams.ygRoot, inParams.uri) + + mclagObj := getMclagRoot(inParams.ygRoot) + if mclagObj.Interfaces == nil { + return res_map, err + } + + for intfId, _ := range mclagObj.Interfaces.Interface { + intf := mclagObj.Interfaces.Interface[intfId] + if intf != nil { + var mclagdomainId int + if intf.Config != nil { + mclagdomainId = int(*intf.Config.MclagDomainId) + } else { + // DomainId info NOT available from URI or body. So make db query. + mclagIntfKeys, _ := inParams.d.GetKeys(&db.TableSpec{Name: "MCLAG_INTERFACE"}) + if len(mclagIntfKeys) > 0 { + for _, intfKey := range mclagIntfKeys { + if intfKey.Get(1) == *intf.Name { + domainid, _ := strconv.ParseUint(intfKey.Get(0), 10, 32) + mclagdomainId = int(domainid) + } + } + } + } + mclagIntfKey := strconv.Itoa(mclagdomainId) + "|" + *intf.Name + log.Infof("YangToDb_mclag_interface_subtree_xfmr --> key: %v", mclagIntfKey) + + _, ok := mclagIntfTblMap[mclagIntfKey] + if !ok { + mclagIntfTblMap[mclagIntfKey] = db.Value{Field: make(map[string]string)} + } + mclagIntfTblMap[mclagIntfKey].Field["if_type"] = "PortChannel" + } + } + + res_map["MCLAG_INTERFACE"] = mclagIntfTblMap + return res_map, err +} + +var DbToYang_mclag_interface_subtree_xfmr SubTreeXfmrDbToYang = func(inParams XfmrParams) error { + var err error + data := (*inParams.dbDataMap)[inParams.curDb] + mclagObj := getMclagRoot(inParams.ygRoot) + pathInfo := NewPathInfo(inParams.uri) + + log.Info("DbToYang_mclag_interface_subtree_xfmr: ", data, inParams.ygRoot) + + if isSubtreeRequest(pathInfo.Template, "/openconfig-mclag:mclag/interfaces/interface{name}") { + mclagIntfKeys, _ := inParams.d.GetKeys(&db.TableSpec{Name: "MCLAG_INTERFACE"}) + if len(mclagIntfKeys) > 0 { + for _, intfKey := range mclagIntfKeys { + ifname := intfKey.Get(1) + if ifname == pathInfo.Var("name") && mclagObj.Interfaces != nil { + for k, _ := range mclagObj.Interfaces.Interface { + intfData := mclagObj.Interfaces.Interface[k] + fillMclagIntfDetails(inParams, ifname, intfKey.Get(0), intfData) + } + } + } + } + } else { + var mclagIntfData map[string]map[string]string + + mclagIntfTbl := data["MCLAG_INTERFACE"] + mclagIntfData = make(map[string]map[string]string) + for key, _ := range mclagIntfTbl { + //split key into domain-id and if-name + tokens := strings.Split(key, "|") + ifname := tokens[1] + mclagIntfData[ifname] = make(map[string]string) + mclagIntfData[ifname]["domainid"] = tokens[0] + mclagIntfData[ifname]["ifname"] = ifname + } + + for intfId := range mclagIntfData { + if mclagObj.Interfaces == nil { + ygot.BuildEmptyTree(mclagObj) + } + intfData, _ := mclagObj.Interfaces.NewInterface(intfId) + fillMclagIntfDetails(inParams, mclagIntfData[intfId]["ifname"], mclagIntfData[intfId]["domainid"], intfData) + } + } + + return err +} + +func fillMclagIntfDetails(inParams XfmrParams, ifname string, mclagdomainid string, intfData *ocbinds.OpenconfigMclag_Mclag_Interfaces_Interface) { + if intfData == nil { + return + } + + ygot.BuildEmptyTree(intfData) + + domainid, _ := strconv.ParseUint(mclagdomainid, 10, 32) + did32 := uint32(domainid) + + intfData.Name = &ifname + + if intfData.Config != nil { + intfData.Config.MclagDomainId = &did32 + intfData.Config.Name = &ifname + log.Infof("fillMclagIntfDetails--> filled config container with domain:%v and Interface:%v", did32, ifname) + } + + // Fetch operational data from StateDb and AppDb + stDb := inParams.dbs[db.StateDB] + mclagRemoteIntfEntry, _ := stDb.GetEntry(&db.TableSpec{Name: "MCLAG_REMOTE_INTF_TABLE"}, db.Key{Comp: []string{mclagdomainid + "|" + ifname}}) + operStatus := mclagRemoteIntfEntry.Get("oper_status") + + appDb := inParams.dbs[db.ApplDB] + lagEntry, _ := appDb.GetEntry(&db.TableSpec{Name: "LAG_TABLE"}, db.Key{Comp: []string{ifname}}) + trafficDisable, _ := strconv.ParseBool(lagEntry.Get("traffic_disable")) + + if intfData.State != nil { + ygot.BuildEmptyTree(intfData.State) + + intfData.State.MclagDomainId = &did32 + intfData.State.Name = &ifname + + if intfData.State.Local != nil { + intfData.State.Local.TrafficDisable = &trafficDisable + } + + if intfData.State.Remote != nil { + if operStatus == "up" { + intfData.State.Remote.OperStatus = ocbinds.OpenconfigMclag_Mclag_Interfaces_Interface_State_Remote_OperStatus_OPER_UP + } else if operStatus == "down" { + intfData.State.Remote.OperStatus = ocbinds.OpenconfigMclag_Mclag_Interfaces_Interface_State_Remote_OperStatus_OPER_DOWN + } + } + } + +} + +func getMclagRoot(s *ygot.GoStruct) *ocbinds.OpenconfigMclag_Mclag { + deviceObj := (*s).(*ocbinds.Device) + return deviceObj.Mclag +}