From b7c0d8d35dface8c257b5822492b71ff7658ea46 Mon Sep 17 00:00:00 2001 From: Satoru-Shinohara Date: Tue, 30 Jan 2024 15:44:25 -0500 Subject: [PATCH 01/13] sonic-port xfmr support --- config/transformer/models_list | 4 +- .../openconfig-interfaces-annot.yang | 79 + .../extensions/openconfig-interfaces-ext.yang | 147 ++ models/yang/openconfig-if-ethernet.yang | 102 +- models/yang/sonic/import.mk | 4 +- translib/intf_app.go | 1405 ----------------- translib/intf_app_test.go | 240 --- translib/sys_app.go | 7 + translib/transformer/xfmr_intf.go | 1027 ++++++++++++ 9 files changed, 1364 insertions(+), 1651 deletions(-) create mode 100644 models/yang/annotations/openconfig-interfaces-annot.yang create mode 100644 models/yang/extensions/openconfig-interfaces-ext.yang delete mode 100644 translib/intf_app.go delete mode 100644 translib/intf_app_test.go create mode 100644 translib/transformer/xfmr_intf.go diff --git a/config/transformer/models_list b/config/transformer/models_list index 1789f52c9..3d9c6f152 100644 --- a/config/transformer/models_list +++ b/config/transformer/models_list @@ -2,4 +2,6 @@ openconfig-acl.yang openconfig-acl-annot.yang openconfig-sampling-sflow.yang -openconfig-sampling-sflow-annot.yang +openconfig-if-ethernet.yang +openconfig-interfaces.yang +openconfig-interfaces-annot.yang diff --git a/models/yang/annotations/openconfig-interfaces-annot.yang b/models/yang/annotations/openconfig-interfaces-annot.yang new file mode 100644 index 000000000..5eced557f --- /dev/null +++ b/models/yang/annotations/openconfig-interfaces-annot.yang @@ -0,0 +1,79 @@ +module openconfig-interfaces-annot { + + yang-version "1"; + + namespace "http://openconfig.net/yang/annotation/openconfig-interfaces-annot"; + prefix "oc-interfaces-annot"; + + import sonic-extensions { prefix sonic-ext; } + import openconfig-interfaces { prefix oc-intf; } + + deviation /oc-intf:interfaces/oc-intf:interface { + deviate add { + sonic-ext:key-transformer "intf_tbl_key_xfmr"; + sonic-ext:table-transformer "intf_table_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config { + deviate add { + sonic-ext:subtree-transformer "intf_eth_port_config_xfmr"; + sonic-ext:path-transformer "intf_eth_port_config_path_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state { + deviate add { + sonic-ext:db-name "APPL_DB"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state { + deviate add { + sonic-ext:db-name "APPL_DB"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:auto-negotiate { + deviate add { + sonic-ext:field-transformer "intf_eth_auto_neg_xfmr"; + sonic-ext:field-name "autoneg"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-intf:mtu { + deviate add { + sonic-ext:field-transformer "intf_mtu_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:port-speed { + deviate add { + sonic-ext:field-transformer "intf_eth_port_speed_xfmr"; + sonic-ext:field-name "speed"; + } + } + + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:admin-status { + deviate add { + sonic-ext:field-transformer "intf_admin_status_xfmr"; + sonic-ext:field-name "admin_status"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-intf:enabled { + deviate add { + sonic-ext:field-transformer "intf_enabled_xfmr"; + sonic-ext:field-name "admin_status"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:enabled { + deviate add { + sonic-ext:field-transformer "intf_enabled_xfmr"; + sonic-ext:field-name "admin_status"; + } + } + +} \ No newline at end of file diff --git a/models/yang/extensions/openconfig-interfaces-ext.yang b/models/yang/extensions/openconfig-interfaces-ext.yang new file mode 100644 index 000000000..73b70e46a --- /dev/null +++ b/models/yang/extensions/openconfig-interfaces-ext.yang @@ -0,0 +1,147 @@ +module openconfig-interfaces-ext { + + yang-version "1.1"; + + // namespace + namespace "http://openconfig.net/yang/interfaces/extension"; + + prefix "oc-intf-ext"; + + import openconfig-extensions { prefix oc-ext; } + import openconfig-interfaces { prefix oc-intf; } + import openconfig-vlan { prefix oc-vlan; } + import openconfig-if-ethernet {prefix oc-eth; } + import openconfig-if-aggregate {prefix oc-lag; } + import openconfig-if-tunnel {prefix oc-tun; } + + + organization "SONiC"; + + contact + "SONiC"; + + description + "This module contains collection of yang definitions for extensions to + openconfig-interfaces yang"; + + oc-ext:openconfig-version "0.1.0"; + + revision 2024-01-18 { + description + "Initial version."; + reference "0.1.0"; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-intf:loopback-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-vlan:tpid { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-intf:type { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:loopback-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:oper-status { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:last-change { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:counters { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:type { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:ifindex { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:logical { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-vlan:tpid { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:hold-time { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-eth:mac-address { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-eth:duplex-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-eth:enable-flow-control { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-lag:aggregate-id { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:mac-address { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:duplex-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:enable-flow-control { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:counters { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-lag:aggregate-id { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:hw-mac-address { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:negotiated-duplex-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:negotiated-port-speed { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-vlan:switched-vlan { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-tun:tunnel { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-lag:aggregation { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-vlan:routed-vlan { + deviate not-supported; + } + +} \ No newline at end of file diff --git a/models/yang/openconfig-if-ethernet.yang b/models/yang/openconfig-if-ethernet.yang index e917bba4d..4e15bd28a 100644 --- a/models/yang/openconfig-if-ethernet.yang +++ b/models/yang/openconfig-if-ethernet.yang @@ -24,7 +24,83 @@ module openconfig-if-ethernet { "Model for managing Ethernet interfaces -- augments the OpenConfig model for interface configuration and state."; - oc-ext:openconfig-version "2.6.2"; + oc-ext:openconfig-version "2.13.0"; + + revision "2023-03-10" { + description + "Allow Ethernet configuration parameters to be + used for aggregate (LAG) interfaces."; + reference "2.13.0"; + } + + revision "2022-04-20" { + description + "Remove unused import"; + reference "2.12.2"; + } + + revision "2021-07-20" { + description + "Fix typo in hardware MAC address description."; + reference "2.12.1"; + } + + revision "2021-07-07" { + description + "Add support for configuring fec-mode per interface."; + reference "2.12.0"; + } + + revision "2021-06-16" { + description + "Remove trailing whitespace."; + reference "2.11.1"; + } + + revision "2021-06-09" { + description + "Add support for standalone link training."; + reference "2.11.0"; + } + + revision "2021-05-17" { + description + "Add ethernet counters: in-carrier-errors, + in-interrupted-tx, in-late-collision, in-mac-errors-rx, + in-single-collision, in-symbol-error and out-mac-errors-tx"; + reference "2.10.0"; + } + + revision "2021-03-30" { + description + "Add counter for drops due to oversized frames."; + reference "2.9.0"; + } + + revision "2020-05-06" { + description + "Minor formatting fix."; + reference "2.8.1"; + } + + revision "2020-05-06" { + description + "Add 200G, 400G, 600G and 800G Ethernet speeds."; + reference "2.8.0"; + } + + revision "2020-05-05" { + description + "Fix when statement checks to use rw paths when + from a rw context."; + reference "2.7.3"; + } + + revision "2019-04-16" { + description + "Update import prefix for iana-if-type module"; + reference "2.7.2"; + } revision "2018-11-21" { description @@ -146,6 +222,26 @@ module openconfig-if-ethernet { description "100 Gbps Ethernet"; } + identity SPEED_200GB { + base ETHERNET_SPEED; + description "200 Gbps Ethernet"; + } + + identity SPEED_400GB { + base ETHERNET_SPEED; + description "400 Gbps Ethernet"; + } + + identity SPEED_600GB { + base ETHERNET_SPEED; + description "600 Gbps Ethernet"; + } + + identity SPEED_800GB { + base ETHERNET_SPEED; + description "800 Gbps Ethernet"; + } + identity SPEED_UNKNOWN { base ETHERNET_SPEED; description @@ -349,7 +445,7 @@ module openconfig-if-ethernet { leaf hw-mac-address { type oc-yang:mac-address; description - "Represenets the 'burned-in', or system-assigned, MAC + "Represents the 'burned-in', or system-assigned, MAC address for the Ethernet interface."; } @@ -382,9 +478,7 @@ module openconfig-if-ethernet { description "Ethernet interface counters"; uses ethernet-interface-state-counters; - } - } // data definition statements diff --git a/models/yang/sonic/import.mk b/models/yang/sonic/import.mk index e52ff765f..7cac2d4e0 100644 --- a/models/yang/sonic/import.mk +++ b/models/yang/sonic/import.mk @@ -5,4 +5,6 @@ # or glob patterns of basenames (like sonic-telemetry*.yang) can be specified. # Other sonic yangs referred by these will also be copied. # -SONICYANG_IMPORTS += sonic-sflow.yang \ No newline at end of file +SONICYANG_IMPORTS += sonic-sflow.yang +SONICYANG_IMPORTS += sonic-interface.yang +SONICYANG_IMPORTS += sonic-port.yang \ No newline at end of file diff --git a/translib/intf_app.go b/translib/intf_app.go deleted file mode 100644 index 4836b1746..000000000 --- a/translib/intf_app.go +++ /dev/null @@ -1,1405 +0,0 @@ -////////////////////////////////////////////////////////////////////////// -// -// 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 translib - -import ( - "errors" - "fmt" - "net" - "reflect" - "regexp" - "strconv" - "strings" - "unsafe" - - "github.com/Azure/sonic-mgmt-common/translib/db" - "github.com/Azure/sonic-mgmt-common/translib/ocbinds" - "github.com/Azure/sonic-mgmt-common/translib/path" - "github.com/Azure/sonic-mgmt-common/translib/tlerr" - log "github.com/golang/glog" - "github.com/openconfig/ygot/ygot" -) - -type reqType int - -const ( - opCreate reqType = iota + 1 - opDelete - opUpdate -) - -type dbEntry struct { - op reqType - entry db.Value -} - -const ( - PORT = "PORT" - PORT_TABLE = "PORT_TABLE" - INTERFACE = "INTERFACE" - COUNTERS_NAME_MAP = "COUNTERS_PORT_NAME_MAP" -) - -const ( - PORT_INDEX = "index" - PORT_MTU = "mtu" - PORT_ADMIN_STATUS = "admin_status" - PORT_SPEED = "speed" - PORT_DESC = "description" - PORT_OPER_STATUS = "oper_status" -) - -// intf_app supports physical ports only; hence consider only -// "EthernetX" fields from COUNTERS_PORT_NAME_MAP -const countersMapFieldPattern = "Ethernet*" - -type Table int - -const ( - IF_TABLE_MAP Table = iota - PORT_STAT_MAP -) - -type IntfApp struct { - path *PathInfo - reqData []byte - ygotRoot *ygot.GoStruct - ygotTarget *interface{} - - respJSON interface{} - allIpKeys []db.Key - - appDB *db.DB - countersDB *db.DB - - ifTableMap map[string]dbEntry - ifIPTableMap map[string]map[string]dbEntry - portOidMap dbEntry - portStatMap map[string]dbEntry - - portTs *db.TableSpec - portTblTs *db.TableSpec - intfIPTs *db.TableSpec - intfIPTblTs *db.TableSpec - intfCountrTblTs *db.TableSpec - portOidCountrTblTs *db.TableSpec -} - -func init() { - log.Info("Init called for INTF module") - err := register("/openconfig-interfaces:interfaces", - &appInfo{appType: reflect.TypeOf(IntfApp{}), - ygotRootType: reflect.TypeOf(ocbinds.OpenconfigInterfaces_Interfaces{}), - isNative: false}) - if err != nil { - log.Fatal("Register INTF app module with App Interface failed with error=", err) - } - - err = addModel(&ModelData{Name: "openconfig-interfaces", - Org: "OpenConfig working group", - Ver: "1.0.2"}) - if err != nil { - log.Fatal("Adding model data to appinterface failed with error=", err) - } -} - -func (app *IntfApp) initialize(data appData) { - log.Info("initialize:if:path =", data.path) - - app.path = NewPathInfo(data.path) - app.reqData = data.payload - app.ygotRoot = data.ygotRoot - app.ygotTarget = data.ygotTarget - - app.portTs = &db.TableSpec{Name: "PORT"} - app.portTblTs = &db.TableSpec{Name: "PORT_TABLE"} - app.intfIPTs = &db.TableSpec{Name: "INTERFACE"} - app.intfIPTblTs = &db.TableSpec{Name: "INTF_TABLE", CompCt: 2} - app.intfCountrTblTs = &db.TableSpec{Name: "COUNTERS"} - app.portOidCountrTblTs = &db.TableSpec{Name: "COUNTERS_PORT_NAME_MAP"} - - app.ifTableMap = make(map[string]dbEntry) - app.ifIPTableMap = make(map[string]map[string]dbEntry) - app.portStatMap = make(map[string]dbEntry) -} - -func (app *IntfApp) getAppRootObject() *ocbinds.OpenconfigInterfaces_Interfaces { - deviceObj := (*app.ygotRoot).(*ocbinds.Device) - return deviceObj.Interfaces -} - -func (app *IntfApp) translateCreate(d *db.DB) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - log.Info("translateCreate:intf:path =", app.path) - - err = errors.New("Not implemented") - return keys, err -} - -func (app *IntfApp) translateUpdate(d *db.DB) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - - log.Info("translateUpdate:intf:path =", app.path) - - keys, err = app.translateCommon(d, opUpdate) - - if err != nil { - log.Info("Something wrong:=", err) - } - - return keys, err -} - -func (app *IntfApp) translateReplace(d *db.DB) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - log.Info("translateReplace:intf:path =", app.path) - err = errors.New("Not implemented") - return keys, err -} - -func (app *IntfApp) translateDelete(d *db.DB) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - pathInfo := app.path - - log.Infof("Received Delete for path %s; vars=%v", pathInfo.Template, pathInfo.Vars) - - intfObj := app.getAppRootObject() - - targetUriPath, err := getYangPathFromUri(app.path.Path) - log.Info("uripath:=", targetUriPath) - log.Info("err:=", err) - - if intfObj.Interface != nil && len(intfObj.Interface) > 0 { - log.Info("len:=", len(intfObj.Interface)) - for ifKey, _ := range intfObj.Interface { - log.Info("Name:=", ifKey) - intf := intfObj.Interface[ifKey] - - if intf.Subinterfaces == nil { - continue - } - subIf := intf.Subinterfaces.Subinterface[0] - if subIf != nil { - if subIf.Ipv4 != nil && subIf.Ipv4.Addresses != nil { - for ip, _ := range subIf.Ipv4.Addresses.Address { - addr := subIf.Ipv4.Addresses.Address[ip] - if addr != nil { - ipAddr := addr.Ip - log.Info("IPv4 address = ", *ipAddr) - if !validIPv4(*ipAddr) { - errStr := "Invalid IPv4 address " + *ipAddr - ipValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ipValidErr - } - err = app.validateIp(d, ifKey, *ipAddr) - if err != nil { - errStr := "Invalid IPv4 address " + *ipAddr - ipValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ipValidErr - } - } - } - } - if subIf.Ipv6 != nil && subIf.Ipv6.Addresses != nil { - for ip, _ := range subIf.Ipv6.Addresses.Address { - addr := subIf.Ipv6.Addresses.Address[ip] - if addr != nil { - ipAddr := addr.Ip - log.Info("IPv6 address = ", *ipAddr) - if !validIPv6(*ipAddr) { - errStr := "Invalid IPv6 address " + *ipAddr - ipValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ipValidErr - } - err = app.validateIp(d, ifKey, *ipAddr) - if err != nil { - errStr := "Invalid IPv6 address:" + *ipAddr - ipValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ipValidErr - } - } - } - } - } else { - err = errors.New("Only subinterface index 0 is supported") - return keys, err - } - } - } else { - err = errors.New("Not implemented") - } - return keys, err -} - -func (app *IntfApp) translateGet(dbs [db.MaxDB]*db.DB) error { - var err error - log.Info("translateGet:intf:path =", app.path) - return err -} - -func (app *IntfApp) translateAction(dbs [db.MaxDB]*db.DB) error { - err := errors.New("Not supported") - return err -} - -func (app *IntfApp) translateSubscribe(req translateSubRequest) (translateSubResponse, error) { - ymap := yangMapTree{ - subtree: map[string]*yangMapTree{ - "interface": { - mapFunc: app.translateSubscribeIntfList, - subtree: map[string]*yangMapTree{ - "state": { - mapFunc: app.translateSubscribeIntfState, - subtree: map[string]*yangMapTree{ - "counters": { - mapFunc: app.translateSubscribeIntfStats, - }, - }, - }, - "subinterfaces/subinterface": { - mapFunc: app.translateSubscribeSubIntf, - subtree: map[string]*yangMapTree{ - "openconfig-if-ip:ipv4/addresses/address": { - mapFunc: app.translateSubscribeIntfIP, - }, - "openconfig-if-ip:ipv6/addresses/address": { - mapFunc: app.translateSubscribeIntfIP, - }, - }, - }, - }}}} - - nb := notificationInfoBuilder{ - pathInfo: NewPathInfo(req.path), - yangMap: ymap, - } - return nb.Build() -} - -func (app *IntfApp) translateSubscribeIntfList(nb *notificationInfoBuilder) error { - name := nb.pathInfo.StringVar("name", "*") - nb.New().PathKey("name", name).Table(db.ConfigDB, PORT).Key(name) - if nb.SetFieldPrefix("config") { - nb.Field("mtu", PORT_MTU) - nb.Field("description", PORT_DESC) - nb.Field("enabled", PORT_ADMIN_STATUS) - } - if nb.SetFieldPrefix("openconfig-if-ethernet:ethernet/config") { - nb.Field("port-speed", PORT_SPEED) - } - if nb.SetFieldPrefix("openconfig-if-ethernet:ethernet/state") { - nb.Field("port-speed", PORT_SPEED) - } - return nil -} - -func (app *IntfApp) translateSubscribeIntfState(nb *notificationInfoBuilder) error { - name := nb.pathInfo.StringVar("name", "*") - nb.New().Table(db.ApplDB, PORT_TABLE).Key(name) - if nb.SetFieldPrefix("") { - nb.Field("ifindex", PORT_INDEX) - nb.Field("mtu", PORT_MTU) - nb.Field("description", PORT_DESC) - nb.Field("enabled", PORT_ADMIN_STATUS) - nb.Field("admin-status", PORT_ADMIN_STATUS) - nb.Field("oper-status", PORT_OPER_STATUS) - } - return nil -} - -func (app *IntfApp) translateSubscribeIntfStats(nb *notificationInfoBuilder) error { - name := nb.pathInfo.StringVar("name", "*") - fieldPattern := name - if name == "*" { - fieldPattern = countersMapFieldPattern - } - nb.New().Table(db.CountersDB, COUNTERS_NAME_MAP).FieldScan(fieldPattern) - return nil -} - -func (app *IntfApp) translateSubscribeSubIntf(nb *notificationInfoBuilder) error { - index := nb.pathInfo.StringVar("index", "*") - if index != "*" && index != "0" { - return tlerr.InvalidArgs("invalid subinterface index: %s", index) - } - nb.PathKey("index", "0") - return nil -} - -func (app *IntfApp) translateSubscribeIntfIP(nb *notificationInfoBuilder) error { - name := nb.pathInfo.StringVar("name", "*") - ipV := 4 // 4 or 6 - if p := path.GetElemAt(nb.currentPath, 4); strings.HasSuffix(p, "ipv6") { - ipV = 6 - } - - addr := nb.pathInfo.StringVar("ip", "*") - var addrDbPattern string - if addr != "*" { - if (ipV == 4 && !validIPv4(addr)) || (ipV == 6 && !validIPv6(addr)) { - return tlerr.InvalidArgs("not a valid ipv%d address: %s", ipV, addr) - } - addrDbPattern = addr + "/*" - } else if ipV == 4 { - addrDbPattern = "*.*.*.*/*" - } else { - addrDbPattern = "*:*/*" // ipv6 address will have at least 1 colon - } - - nb.New().PathKey("ip", addr).Table(db.ConfigDB, INTERFACE).Key(name, addrDbPattern) - if nb.SetFieldPrefix("config") { - nb.Field("prefix-length", "") - } - if nb.SetFieldPrefix("state") { - nb.Field("prefix-length", "") - } - return nil -} - -func (app *IntfApp) processSubscribe(req processSubRequest) (processSubResponse, error) { - resp := processSubResponse{ - path: req.path, - } - switch req.table.Name { - case PORT, PORT_TABLE, COUNTERS_NAME_MAP: - path.SetKeyAt(resp.path, 1, "name", req.key.Get(0)) - case INTERFACE: - if req.key.Len() != 2 { - return resp, tlerr.New("unsupported interface key: %v", req.key) - } - path.SetKeyAt(resp.path, 1, "name", req.key.Get(0)) - path.SetKeyAt(resp.path, 3, "index", "0") - path.SetKeyAt(resp.path, 6, "ip", strings.Split(req.key.Get(1), "/")[0]) // trim subnet mask - default: - return resp, tlerr.New("unsupported table: %s", req.table.Name) - } - return resp, nil -} - -func (app *IntfApp) processCreate(d *db.DB) (SetResponse, error) { - var err error - var resp SetResponse - - log.Info("processCreate:intf:path =", app.path) - log.Info("ProcessCreate: Target Type is " + reflect.TypeOf(*app.ygotTarget).Elem().Name()) - - err = errors.New("Not implemented") - return resp, err -} - -func (app *IntfApp) processUpdate(d *db.DB) (SetResponse, error) { - - log.Infof("Calling processCommon()") - - resp, err := app.processCommon(d) - return resp, err -} - -func (app *IntfApp) processReplace(d *db.DB) (SetResponse, error) { - var err error - var resp SetResponse - log.Info("processReplace:intf:path =", app.path) - err = errors.New("Not implemented") - return resp, err -} - -func (app *IntfApp) processDelete(d *db.DB) (SetResponse, error) { - var err error - var resp SetResponse - log.Info("processDelete:intf:path =", app.path) - - if len(app.ifIPTableMap) == 0 { - return resp, err - } - for ifKey, entrylist := range app.ifIPTableMap { - for ip, _ := range entrylist { - err = d.DeleteEntry(app.intfIPTs, db.Key{Comp: []string{ifKey, ip}}) - log.Infof("Deleted IP : %s for Interface : %s", ip, ifKey) - } - } - return resp, err -} - -/* Note : Registration already happened, followed by filling the internal DS and filling the JSON */ -func (app *IntfApp) processGet(dbs [db.MaxDB]*db.DB, fmtType TranslibFmtType) (GetResponse, error) { - - var err error - var payload []byte - pathInfo := app.path - - log.Infof("Received GET for path %s; template: %s vars=%v", pathInfo.Path, pathInfo.Template, pathInfo.Vars) - app.appDB = dbs[db.ApplDB] - app.countersDB = dbs[db.CountersDB] - - intfObj := app.getAppRootObject() - - targetUriPath, err := getYangPathFromUri(app.path.Path) - log.Info("URI Path = ", targetUriPath) - - if isSubtreeRequest(targetUriPath, "/openconfig-interfaces:interfaces/interface") { - /* Request for a specific interface */ - if intfObj.Interface != nil && len(intfObj.Interface) > 0 { - /* Interface name is the key */ - for ifKey, _ := range intfObj.Interface { - log.Info("Interface Name = ", ifKey) - ifInfo := intfObj.Interface[ifKey] - /* Filling Interface Info to internal DS */ - err = app.convertDBIntfInfoToInternal(app.appDB, ifKey, db.Key{Comp: []string{ifKey}}) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - - /*Check if the request is for a specific attribute in Interfaces state container*/ - oc_val := &ocbinds.OpenconfigInterfaces_Interfaces_Interface_State{} - ok, e := app.getSpecificAttr(targetUriPath, ifKey, oc_val) - if ok { - if e != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, e - } - - ifInfo.State = oc_val - continue - } - - /* Filling the counter Info to internal DS */ - err = app.getPortOidMapForCounters(app.countersDB) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - err = app.convertDBIntfCounterInfoToInternal(app.countersDB, ifKey) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - - /*Check if the request is for a specific attribute in Interfaces state COUNTERS container*/ - counter_val := &ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_Counters{} - ok, e = app.getSpecificCounterAttr(targetUriPath, ifKey, counter_val) - if ok { - if e != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, e - } - - ifInfo.State = &ocbinds.OpenconfigInterfaces_Interfaces_Interface_State{Counters: counter_val} - continue - } - - /* Filling Interface IP info to internal DS */ - err = app.convertDBIntfIPInfoToInternal(app.appDB, ifKey) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - - /* Filling the tree with the info we have in Internal DS */ - ygot.BuildEmptyTree(ifInfo) - if *app.ygotTarget == ifInfo.State { - ygot.BuildEmptyTree(ifInfo.State) - } - app.convertInternalToOCIntfInfo(&ifKey, ifInfo) - } - } - - return generateGetResponse(pathInfo.Path, app.ygotRoot, fmtType) - } - - /* Get all Interfaces */ - if isSubtreeRequest(targetUriPath, "/openconfig-interfaces:interfaces") { - log.Info("Get all Interfaces request!") - /* Filling Interface Info to internal DS */ - err = app.convertDBIntfInfoToInternal(app.appDB, "", db.Key{}) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - /* Filling Interface IP info to internal DS */ - err = app.convertDBIntfIPInfoToInternal(app.appDB, "") - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - /* Filling the counter Info to internal DS */ - err = app.getPortOidMapForCounters(app.countersDB) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - err = app.convertDBIntfCounterInfoToInternal(app.countersDB, "") - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - ygot.BuildEmptyTree(intfObj) - for ifKey, _ := range app.ifTableMap { - log.Info("If Key = ", ifKey) - ifInfo, err := intfObj.NewInterface(ifKey) - if err != nil { - log.Errorf("Creation of interface subtree for %s failed!", ifKey) - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - ygot.BuildEmptyTree(ifInfo) - app.convertInternalToOCIntfInfo(&ifKey, ifInfo) - } - } - - return generateGetResponse(pathInfo.Path, app.ygotRoot, fmtType) -} - -func (app *IntfApp) processAction(dbs [db.MaxDB]*db.DB) (ActionResponse, error) { - var resp ActionResponse - err := errors.New("Not implemented") - - return resp, err -} - -/* Checking IP adderss is v4 */ -func validIPv4(ipAddress string) bool { - ipAddress = strings.Trim(ipAddress, " ") - - re, _ := regexp.Compile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`) - if re.MatchString(ipAddress) { - return true - } - return false -} - -/* Checking IP address is v6 */ -func validIPv6(ip6Address string) bool { - ip6Address = strings.Trim(ip6Address, " ") - re, _ := regexp.Compile(`(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`) - if re.MatchString(ip6Address) { - return true - } - return false -} - -func (app *IntfApp) doGetAllIpKeys(d *db.DB, dbSpec *db.TableSpec) ([]db.Key, error) { - - var keys []db.Key - - intfTable, err := d.GetTable(dbSpec) - if err != nil { - return keys, err - } - - keys, err = intfTable.GetKeys() - log.Infof("Found %d INTF table keys", len(keys)) - return keys, err -} - -func (app *IntfApp) getSpecificAttr(targetUriPath string, ifKey string, oc_val *ocbinds.OpenconfigInterfaces_Interfaces_Interface_State) (bool, error) { - switch targetUriPath { - case "/openconfig-interfaces:interfaces/interface/state/oper-status": - val, e := app.getIntfAttr(ifKey, PORT_OPER_STATUS, IF_TABLE_MAP) - if len(val) > 0 { - switch val { - case "up": - oc_val.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UP - case "down": - oc_val.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_DOWN - default: - oc_val.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UNSET - } - return true, nil - } else { - return true, e - } - case "/openconfig-interfaces:interfaces/interface/state/admin-status": - val, e := app.getIntfAttr(ifKey, PORT_ADMIN_STATUS, IF_TABLE_MAP) - if len(val) > 0 { - switch val { - case "up": - oc_val.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UP - case "down": - oc_val.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_DOWN - default: - oc_val.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UNSET - } - return true, nil - } else { - return true, e - } - case "/openconfig-interfaces:interfaces/interface/state/mtu": - val, e := app.getIntfAttr(ifKey, PORT_MTU, IF_TABLE_MAP) - if len(val) > 0 { - v, e := strconv.ParseUint(val, 10, 16) - if e == nil { - oc_val.Mtu = (*uint16)(unsafe.Pointer(&v)) - return true, nil - } - } - return true, e - case "/openconfig-interfaces:interfaces/interface/state/ifindex": - val, e := app.getIntfAttr(ifKey, PORT_INDEX, IF_TABLE_MAP) - if len(val) > 0 { - v, e := strconv.ParseUint(val, 10, 32) - if e == nil { - oc_val.Ifindex = (*uint32)(unsafe.Pointer(&v)) - return true, nil - } - } - return true, e - case "/openconfig-interfaces:interfaces/interface/state/description": - val, e := app.getIntfAttr(ifKey, PORT_DESC, IF_TABLE_MAP) - if e == nil { - oc_val.Description = &val - return true, nil - } - return true, e - - default: - log.Infof(targetUriPath + " - Not an interface state attribute") - } - return false, nil -} - -func (app *IntfApp) getSpecificCounterAttr(targetUriPath string, ifKey string, counter_val *ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_Counters) (bool, error) { - - var e error - - switch targetUriPath { - case "/openconfig-interfaces:interfaces/interface/state/counters/in-octets": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_OCTETS", &counter_val.InOctets) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-unicast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_UCAST_PKTS", &counter_val.InUnicastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-broadcast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_BROADCAST_PKTS", &counter_val.InBroadcastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-multicast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_MULTICAST_PKTS", &counter_val.InMulticastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-errors": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_ERRORS", &counter_val.InErrors) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-discards": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_DISCARDS", &counter_val.InDiscards) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-pkts": - var inNonUCastPkt, inUCastPkt *uint64 - var in_pkts uint64 - - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS", &inNonUCastPkt) - if e == nil { - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_UCAST_PKTS", &inUCastPkt) - if e != nil { - return true, e - } - in_pkts = *inUCastPkt + *inNonUCastPkt - counter_val.InPkts = &in_pkts - return true, e - } else { - return true, e - } - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-octets": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_OCTETS", &counter_val.OutOctets) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-unicast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_UCAST_PKTS", &counter_val.OutUnicastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-broadcast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_BROADCAST_PKTS", &counter_val.OutBroadcastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-multicast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_MULTICAST_PKTS", &counter_val.OutMulticastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-errors": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_ERRORS", &counter_val.OutErrors) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-discards": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_DISCARDS", &counter_val.OutDiscards) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-pkts": - var outNonUCastPkt, outUCastPkt *uint64 - var out_pkts uint64 - - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS", &outNonUCastPkt) - if e == nil { - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_UCAST_PKTS", &outUCastPkt) - if e != nil { - return true, e - } - out_pkts = *outUCastPkt + *outNonUCastPkt - counter_val.OutPkts = &out_pkts - return true, e - } else { - return true, e - } - - default: - log.Infof(targetUriPath + " - Not an interface state counter attribute") - } - return false, nil -} - -func (app *IntfApp) getCounters(ifKey string, attr string, counter_val **uint64) error { - val, e := app.getIntfAttr(ifKey, attr, PORT_STAT_MAP) - if len(val) > 0 { - v, e := strconv.ParseUint(val, 10, 64) - if e == nil { - *counter_val = &v - return nil - } - } - return e -} - -func (app *IntfApp) getIntfAttr(ifName string, attr string, table Table) (string, error) { - - var ok bool = false - var entry dbEntry - - if table == IF_TABLE_MAP { - entry, ok = app.ifTableMap[ifName] - } else if table == PORT_STAT_MAP { - entry, ok = app.portStatMap[ifName] - } else { - return "", errors.New("Unsupported table") - } - - if ok { - ifData := entry.entry - - if val, ok := ifData.Field[attr]; ok { - return val, nil - } - } - return "", errors.New("Attr " + attr + "doesn't exist in IF table Map!") -} - -func (app *IntfApp) shouldLoad(p string) bool { - return strings.HasPrefix(p, app.path.Template) || strings.HasPrefix(app.path.Template, p) -} - -/*********** Translation Helper fn to convert DB Interface info to Internal DS ***********/ -func (app *IntfApp) getPortOidMapForCounters(dbCl *db.DB) error { - if !app.shouldLoad("/openconfig-interfaces:interfaces/interface{}/state/counters") { - return nil - } - - var err error - ifCountInfo, err := dbCl.GetMapAll(app.portOidCountrTblTs) - if err != nil { - log.Error("Port-OID (Counters) get for all the interfaces failed!") - return err - } - if ifCountInfo.IsPopulated() { - app.portOidMap.entry = ifCountInfo - } else { - return errors.New("Get for OID info from all the interfaces from Counters DB failed!") - } - return err -} - -func (app *IntfApp) convertDBIntfCounterInfoToInternal(dbCl *db.DB, ifKey string) error { - if !app.shouldLoad("/openconfig-interfaces:interfaces/interface{}/state/counters") { - return nil - } - - var err error - if len(ifKey) > 0 { - oid := app.portOidMap.entry.Field[ifKey] - log.Infof("OID : %s received for Interface : %s", oid, ifKey) - - /* Get the statistics for the port */ - var ifStatKey db.Key - ifStatKey.Comp = []string{oid} - - ifStatInfo, err := dbCl.GetEntry(app.intfCountrTblTs, ifStatKey) - if err != nil { - log.Infof("Fetching port-stat for port : %s failed!", ifKey) - return err - } - app.portStatMap[ifKey] = dbEntry{entry: ifStatInfo} - } else { - for ifKey, _ := range app.ifTableMap { - app.convertDBIntfCounterInfoToInternal(dbCl, ifKey) - } - } - return err -} - -func (app *IntfApp) validateInterface(dbCl *db.DB, ifName string, ifKey db.Key) error { - var err error - if len(ifName) == 0 { - return errors.New("Empty Interface name") - } - app.portTblTs = &db.TableSpec{Name: "PORT_TABLE"} - _, err = dbCl.GetEntry(app.portTblTs, ifKey) - if err != nil { - log.Errorf("Error found on fetching Interface info from App DB for If Name : %s", ifName) - errStr := "Invalid Interface:" + ifName - err = tlerr.InvalidArgsError{Format: errStr} - return err - } - return err -} - -func (app *IntfApp) convertDBIntfInfoToInternal(dbCl *db.DB, ifName string, ifKey db.Key) error { - - var err error - /* Fetching DB data for a specific Interface */ - if len(ifName) > 0 { - log.Info("Updating Interface info from APP-DB to Internal DS for Interface name : ", ifName) - ifInfo, err := dbCl.GetEntry(app.portTblTs, ifKey) - if err != nil { - log.Errorf("Error found on fetching Interface info from App DB for If Name : %s", ifName) - errStr := "Invalid Interface:" + ifName - err = tlerr.InvalidArgsError{Format: errStr} - return err - } - if ifInfo.IsPopulated() { - log.Info("Interface Info populated for ifName : ", ifName) - app.ifTableMap[ifName] = dbEntry{entry: ifInfo} - } else { - return errors.New("Populating Interface info for " + ifName + "failed") - } - } else { - log.Info("App-DB get for all the interfaces") - tbl, err := dbCl.GetTable(app.portTblTs) - if err != nil { - log.Error("App-DB get for list of interfaces failed!") - return err - } - keys, _ := tbl.GetKeys() - for _, key := range keys { - app.convertDBIntfInfoToInternal(dbCl, key.Get(0), db.Key{Comp: []string{key.Get(0)}}) - } - } - return err -} - -/*********** Translation Helper fn to convert DB Interface IP info to Internal DS ***********/ -func (app *IntfApp) convertDBIntfIPInfoToInternal(dbCl *db.DB, ifName string) error { - if !app.shouldLoad("/openconfig-interfaces:interfaces/interface{}/subinterfaces") { - return nil - } - - var err error - log.Info("Updating Interface IP Info from APP-DB to Internal DS for Interface Name : ", ifName) - app.allIpKeys, _ = app.doGetAllIpKeys(dbCl, app.intfIPTblTs) - - for _, key := range app.allIpKeys { - if len(key.Comp) <= 1 { - continue - } - ipInfo, err := dbCl.GetEntry(app.intfIPTblTs, key) - if err != nil { - log.Errorf("Error found on fetching Interface IP info from App DB for Interface Name : %s", ifName) - return err - } - if len(app.ifIPTableMap[key.Get(0)]) == 0 { - app.ifIPTableMap[key.Get(0)] = make(map[string]dbEntry) - app.ifIPTableMap[key.Get(0)][key.Get(1)] = dbEntry{entry: ipInfo} - } else { - app.ifIPTableMap[key.Get(0)][key.Get(1)] = dbEntry{entry: ipInfo} - } - } - return err -} - -func (app *IntfApp) convertInternalToOCIntfInfo(ifName *string, ifInfo *ocbinds.OpenconfigInterfaces_Interfaces_Interface) { - app.convertInternalToOCIntfAttrInfo(ifName, ifInfo) - app.convertInternalToOCIntfIPAttrInfo(ifName, ifInfo) - app.convertInternalToOCPortStatInfo(ifName, ifInfo) -} - -func (app *IntfApp) convertInternalToOCIntfAttrInfo(ifName *string, ifInfo *ocbinds.OpenconfigInterfaces_Interfaces_Interface) { - - /* Handling the Interface attributes */ - if entry, ok := app.ifTableMap[*ifName]; ok { - ifData := entry.entry - - name := *ifName - ifInfo.Config.Name = &name - ifInfo.State.Name = &name - - for ifAttr := range ifData.Field { - switch ifAttr { - case PORT_ADMIN_STATUS: - adminStatus := ifData.Get(ifAttr) - ifInfo.State.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_DOWN - if adminStatus == "up" { - ifInfo.State.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UP - } - case PORT_OPER_STATUS: - operStatus := ifData.Get(ifAttr) - ifInfo.State.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_DOWN - if operStatus == "up" { - ifInfo.State.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UP - } - case PORT_DESC: - descVal := ifData.Get(ifAttr) - descr := new(string) - *descr = descVal - ifInfo.Config.Description = descr - ifInfo.State.Description = descr - case PORT_MTU: - mtuStr := ifData.Get(ifAttr) - mtuVal, err := strconv.Atoi(mtuStr) - mtu := new(uint16) - *mtu = uint16(mtuVal) - if err == nil { - ifInfo.Config.Mtu = mtu - ifInfo.State.Mtu = mtu - } - case PORT_SPEED: - speed := ifData.Get(ifAttr) - var speedEnum ocbinds.E_OpenconfigIfEthernet_ETHERNET_SPEED - - switch speed { - case "2500": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_2500MB - case "1000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_1GB - case "5000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_5GB - case "10000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_10GB - case "25000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_25GB - case "40000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_40GB - case "50000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_50GB - case "100000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_100GB - default: - log.Infof("Not supported speed: %s!", speed) - } - ifInfo.Ethernet.Config.PortSpeed = speedEnum - ifInfo.Ethernet.State.PortSpeed = speedEnum - case PORT_INDEX: - ifIdxStr := ifData.Get(ifAttr) - ifIdxNum, err := strconv.Atoi(ifIdxStr) - if err == nil { - ifIdx := new(uint32) - *ifIdx = uint32(ifIdxNum) - ifInfo.State.Ifindex = ifIdx - } - default: - log.Info("Not a valid attribute!") - } - } - } - -} - -func (app *IntfApp) convertInternalToOCIntfIPAttrInfo(ifName *string, ifInfo *ocbinds.OpenconfigInterfaces_Interfaces_Interface) { - - /* Handling the Interface IP attributes */ - subIntf, err := ifInfo.Subinterfaces.NewSubinterface(0) - if err != nil { - log.Error("Creation of subinterface subtree failed!") - return - } - ygot.BuildEmptyTree(subIntf) - if ipMap, ok := app.ifIPTableMap[*ifName]; ok { - for ipKey, _ := range ipMap { - log.Info("IP address = ", ipKey) - ipB, ipNetB, _ := net.ParseCIDR(ipKey) - - v4Flag := false - v6Flag := false - - var v4Address *ocbinds.OpenconfigInterfaces_Interfaces_Interface_Subinterfaces_Subinterface_Ipv4_Addresses_Address - var v6Address *ocbinds.OpenconfigInterfaces_Interfaces_Interface_Subinterfaces_Subinterface_Ipv6_Addresses_Address - - if validIPv4(ipB.String()) { - v4Address, err = subIntf.Ipv4.Addresses.NewAddress(ipB.String()) - v4Flag = true - } else if validIPv6(ipB.String()) { - v6Address, err = subIntf.Ipv6.Addresses.NewAddress(ipB.String()) - v6Flag = true - } else { - log.Error("Invalid IP address " + ipB.String()) - continue - } - - if err != nil { - log.Error("Creation of address subtree failed!") - return - } - if v4Flag { - ygot.BuildEmptyTree(v4Address) - - ipStr := new(string) - *ipStr = ipB.String() - v4Address.Ip = ipStr - v4Address.Config.Ip = ipStr - v4Address.State.Ip = ipStr - - ipNetBNum, _ := ipNetB.Mask.Size() - prfxLen := new(uint8) - *prfxLen = uint8(ipNetBNum) - v4Address.Config.PrefixLength = prfxLen - v4Address.State.PrefixLength = prfxLen - } - if v6Flag { - ygot.BuildEmptyTree(v6Address) - - ipStr := new(string) - *ipStr = ipB.String() - v6Address.Ip = ipStr - v6Address.Config.Ip = ipStr - v6Address.State.Ip = ipStr - - ipNetBNum, _ := ipNetB.Mask.Size() - prfxLen := new(uint8) - *prfxLen = uint8(ipNetBNum) - v6Address.Config.PrefixLength = prfxLen - v6Address.State.PrefixLength = prfxLen - } - } - } -} - -func (app *IntfApp) convertInternalToOCPortStatInfo(ifName *string, ifInfo *ocbinds.OpenconfigInterfaces_Interfaces_Interface) { - if len(app.portStatMap) == 0 { - log.Errorf("Port stat info not present for interface : %s", *ifName) - return - } - if portStatInfo, ok := app.portStatMap[*ifName]; ok { - - inOctet := new(uint64) - inOctetVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_OCTETS"]) - *inOctet = uint64(inOctetVal) - ifInfo.State.Counters.InOctets = inOctet - - inUCastPkt := new(uint64) - inUCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_UCAST_PKTS"]) - *inUCastPkt = uint64(inUCastPktVal) - ifInfo.State.Counters.InUnicastPkts = inUCastPkt - - inNonUCastPkt := new(uint64) - inNonUCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS"]) - *inNonUCastPkt = uint64(inNonUCastPktVal) - - inPkt := new(uint64) - *inPkt = *inUCastPkt + *inNonUCastPkt - ifInfo.State.Counters.InPkts = inPkt - - inBCastPkt := new(uint64) - inBCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_BROADCAST_PKTS"]) - *inBCastPkt = uint64(inBCastPktVal) - ifInfo.State.Counters.InBroadcastPkts = inBCastPkt - - inMCastPkt := new(uint64) - inMCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_MULTICAST_PKTS"]) - *inMCastPkt = uint64(inMCastPktVal) - ifInfo.State.Counters.InMulticastPkts = inMCastPkt - - inErrPkt := new(uint64) - inErrPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_ERRORS"]) - *inErrPkt = uint64(inErrPktVal) - ifInfo.State.Counters.InErrors = inErrPkt - - inDiscPkt := new(uint64) - inDiscPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_DISCARDS"]) - *inDiscPkt = uint64(inDiscPktVal) - ifInfo.State.Counters.InDiscards = inDiscPkt - - outOctet := new(uint64) - outOctetVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_OCTETS"]) - *outOctet = uint64(outOctetVal) - ifInfo.State.Counters.OutOctets = outOctet - - outUCastPkt := new(uint64) - outUCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_UCAST_PKTS"]) - *outUCastPkt = uint64(outUCastPktVal) - ifInfo.State.Counters.OutUnicastPkts = outUCastPkt - - outNonUCastPkt := new(uint64) - outNonUCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS"]) - *outNonUCastPkt = uint64(outNonUCastPktVal) - - outPkt := new(uint64) - *outPkt = *outUCastPkt + *outNonUCastPkt - ifInfo.State.Counters.OutPkts = outPkt - - outBCastPkt := new(uint64) - outBCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_BROADCAST_PKTS"]) - *outBCastPkt = uint64(outBCastPktVal) - ifInfo.State.Counters.OutBroadcastPkts = outBCastPkt - - outMCastPkt := new(uint64) - outMCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_MULTICAST_PKTS"]) - *outMCastPkt = uint64(outMCastPktVal) - ifInfo.State.Counters.OutMulticastPkts = outMCastPkt - - outErrPkt := new(uint64) - outErrPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_ERRORS"]) - *outErrPkt = uint64(outErrPktVal) - ifInfo.State.Counters.OutErrors = outErrPkt - - outDiscPkt := new(uint64) - outDiscPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_DISCARDS"]) - *outDiscPkt = uint64(outDiscPktVal) - ifInfo.State.Counters.OutDiscards = outDiscPkt - } -} - -func (app *IntfApp) translateCommon(d *db.DB, inpOp reqType) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - pathInfo := app.path - - log.Infof("Received UPDATE for path %s; vars=%v", pathInfo.Template, pathInfo.Vars) - - app.allIpKeys, _ = app.doGetAllIpKeys(d, app.intfIPTs) - - intfObj := app.getAppRootObject() - - targetUriPath, err := getYangPathFromUri(app.path.Path) - log.Info("uripath:=", targetUriPath) - log.Info("err:=", err) - - if intfObj.Interface != nil && len(intfObj.Interface) > 0 { - log.Info("len:=", len(intfObj.Interface)) - for ifKey, _ := range intfObj.Interface { - log.Info("Name:=", ifKey) - intf := intfObj.Interface[ifKey] - curr, err := d.GetEntry(app.portTs, db.Key{Comp: []string{ifKey}}) - if err != nil { - errStr := "Invalid Interface:" + ifKey - ifValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ifValidErr - } - if !curr.IsPopulated() { - log.Error("Interface ", ifKey, " doesn't exist in DB") - return keys, errors.New("Interface: " + ifKey + " doesn't exist in DB") - } - if intf.Config != nil { - if intf.Config.Description != nil { - log.Info("Description = ", *intf.Config.Description) - curr.Field["description"] = *intf.Config.Description - } else if intf.Config.Mtu != nil { - log.Info("mtu:= ", *intf.Config.Mtu) - curr.Field["mtu"] = strconv.Itoa(int(*intf.Config.Mtu)) - } else if intf.Config.Enabled != nil { - log.Info("enabled = ", *intf.Config.Enabled) - if *intf.Config.Enabled == true { - curr.Field["admin_status"] = "up" - } else { - curr.Field["admin_status"] = "down" - } - } - log.Info("Writing to db for ", ifKey) - var entry dbEntry - entry.op = opUpdate - entry.entry = curr - - app.ifTableMap[ifKey] = entry - } - if intf.Subinterfaces == nil { - continue - } - subIf := intf.Subinterfaces.Subinterface[0] - if subIf != nil { - if subIf.Ipv4 != nil && subIf.Ipv4.Addresses != nil { - for ip, _ := range subIf.Ipv4.Addresses.Address { - addr := subIf.Ipv4.Addresses.Address[ip] - if addr.Config != nil { - log.Info("Ip:=", *addr.Config.Ip) - log.Info("prefix:=", *addr.Config.PrefixLength) - if !validIPv4(*addr.Config.Ip) { - errStr := "Invalid IPv4 address " + *addr.Config.Ip - err = tlerr.InvalidArgsError{Format: errStr} - return keys, err - } - err = app.translateIpv4(d, ifKey, *addr.Config.Ip, int(*addr.Config.PrefixLength)) - if err != nil { - return keys, err - } - } - } - } - if subIf.Ipv6 != nil && subIf.Ipv6.Addresses != nil { - for ip, _ := range subIf.Ipv6.Addresses.Address { - addr := subIf.Ipv6.Addresses.Address[ip] - if addr.Config != nil { - log.Info("Ip:=", *addr.Config.Ip) - log.Info("prefix:=", *addr.Config.PrefixLength) - if !validIPv6(*addr.Config.Ip) { - errStr := "Invalid IPv6 address " + *addr.Config.Ip - err = tlerr.InvalidArgsError{Format: errStr} - return keys, err - } - err = app.translateIpv4(d, ifKey, *addr.Config.Ip, int(*addr.Config.PrefixLength)) - if err != nil { - return keys, err - } - } - } - } - } else { - err = errors.New("Only subinterface index 0 is supported") - return keys, err - } - } - } else { - err = errors.New("Not implemented") - } - - return keys, err -} - -/* Validates whether the IP exists in the DB */ -func (app *IntfApp) validateIp(dbCl *db.DB, ifName string, ip string) error { - app.allIpKeys, _ = app.doGetAllIpKeys(dbCl, app.intfIPTs) - - for _, key := range app.allIpKeys { - if len(key.Comp) < 2 { - continue - } - if key.Get(0) != ifName { - continue - } - ipAddr, _, _ := net.ParseCIDR(key.Get(1)) - ipStr := ipAddr.String() - if ipStr == ip { - log.Infof("IP address %s exists, updating the DS for deletion!", ipStr) - ipInfo, err := dbCl.GetEntry(app.intfIPTs, key) - if err != nil { - log.Error("Error found on fetching Interface IP info from App DB for Interface Name : ", ifName) - return err - } - if len(app.ifIPTableMap[key.Get(0)]) == 0 { - app.ifIPTableMap[key.Get(0)] = make(map[string]dbEntry) - app.ifIPTableMap[key.Get(0)][key.Get(1)] = dbEntry{entry: ipInfo} - } else { - app.ifIPTableMap[key.Get(0)][key.Get(1)] = dbEntry{entry: ipInfo} - } - return nil - } - } - return errors.New(fmt.Sprintf("IP address : %s doesn't exist!", ip)) -} - -func (app *IntfApp) translateIpv4(d *db.DB, intf string, ip string, prefix int) error { - var err error - var ifsKey db.Key - - ifsKey.Comp = []string{intf} - - ipPref := ip + "/" + strconv.Itoa(prefix) - ifsKey.Comp = []string{intf, ipPref} - - log.Info("ifsKey:=", ifsKey) - - log.Info("Checking for IP overlap ....") - ipA, ipNetA, _ := net.ParseCIDR(ipPref) - - for _, key := range app.allIpKeys { - if len(key.Comp) < 2 { - continue - } - ipB, ipNetB, _ := net.ParseCIDR(key.Get(1)) - - if ipNetA.Contains(ipB) || ipNetB.Contains(ipA) { - log.Info("IP ", ipPref, "overlaps with ", key.Get(1), " of ", key.Get(0)) - - if intf != key.Get(0) { - //IP overlap across different interface, reject - log.Error("IP ", ipPref, " overlaps with ", key.Get(1), " of ", key.Get(0)) - - errStr := "IP " + ipPref + " overlaps with IP " + key.Get(1) + " of Interface " + key.Get(0) - err = tlerr.InvalidArgsError{Format: errStr} - return err - } else { - //IP overlap on same interface, replace - var entry dbEntry - entry.op = opDelete - - log.Info("Entry ", key.Get(1), " on ", intf, " needs to be deleted") - if app.ifIPTableMap[intf] == nil { - app.ifIPTableMap[intf] = make(map[string]dbEntry) - } - app.ifIPTableMap[intf][key.Get(1)] = entry - } - } - } - - //At this point, we need to add the entry to db - { - var entry dbEntry - entry.op = opCreate - - m := make(map[string]string) - m["NULL"] = "NULL" - value := db.Value{Field: m} - entry.entry = value - if app.ifIPTableMap[intf] == nil { - app.ifIPTableMap[intf] = make(map[string]dbEntry) - } - app.ifIPTableMap[intf][ipPref] = entry - } - return err -} - -func (app *IntfApp) processCommon(d *db.DB) (SetResponse, error) { - var err error - var resp SetResponse - - log.Info("processCommon:intf:path =", app.path) - log.Info("ProcessCommon: Target Type is " + reflect.TypeOf(*app.ygotTarget).Elem().Name()) - - for key, entry := range app.ifTableMap { - if entry.op == opUpdate { - log.Info("Updating entry for ", key) - err = d.SetEntry(app.portTs, db.Key{Comp: []string{key}}, entry.entry) - } - } - - for key, entry1 := range app.ifIPTableMap { - ifEntry, err := d.GetEntry(app.intfIPTs, db.Key{Comp: []string{key}}) - if err != nil || !ifEntry.IsPopulated() { - log.Infof("Interface Entry not present for Key:%s for IP config!", key) - m := make(map[string]string) - m["NULL"] = "NULL" - err = d.CreateEntry(app.intfIPTs, db.Key{Comp: []string{key}}, db.Value{Field: m}) - if err != nil { - return resp, err - } - log.Infof("Created Interface entry with Interface name : %s alone!", key) - } - for ip, entry := range entry1 { - if entry.op == opCreate { - log.Info("Creating entry for ", key, ":", ip) - err = d.CreateEntry(app.intfIPTs, db.Key{Comp: []string{key, ip}}, entry.entry) - } else if entry.op == opDelete { - log.Info("Deleting entry for ", key, ":", ip) - err = d.DeleteEntry(app.intfIPTs, db.Key{Comp: []string{key, ip}}) - } - } - } - return resp, err -} diff --git a/translib/intf_app_test.go b/translib/intf_app_test.go deleted file mode 100644 index a3e72a86d..000000000 --- a/translib/intf_app_test.go +++ /dev/null @@ -1,240 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// // -// Copyright 2023 Broadcom. The term Broadcom refers to Broadcom Inc. and/or // -// its subsidiaries. // -// // -// 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 translib - -import ( - "fmt" - "testing" - - "github.com/Azure/sonic-mgmt-common/translib/db" -) - -func TestIntfApp_translateSubscribe(t *testing.T) { - - for _, ifName := range []string{"", "*", "Ethernet123"} { - t.Run(fmt.Sprintf("top[name=%s]", ifName), func(t *testing.T) { - reqPath := "/openconfig-interfaces:interfaces" - if len(ifName) != 0 { - reqPath += fmt.Sprintf("/interface[name=%s]", ifName) - } else { - ifName = "*" - } - - ifPath := fmt.Sprintf("/openconfig-interfaces:interfaces/interface[name=%s]", ifName) - tv := testTranslateSubscribe(t, reqPath) - tv.VerifyCount(1, 4) - tv.VerifyTarget( - ifPath, portConfigNInfo(ifName, portConfigAllFields)) - tv.VerifyChild( - ifPath+"/state", portStateNInfo(ifName, portStateAllFields)) - tv.VerifyChild( - ifPath+"/state/counters", portCountersNInfo(ifName)) - tv.VerifyChild( - ifPath+"/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses/address[ip=*]", - portIpAddrNInfo(ifName, portIpv4KeyPattern)) - tv.VerifyChild( - ifPath+"/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses/address[ip=*]", - portIpAddrNInfo(ifName, portIpv6KeyPattern)) - }) - } - - for _, ifName := range []string{"*", "Ethernet123"} { - tcPrefix := fmt.Sprintf("name=%s|", ifName) - ifPath := fmt.Sprintf("/openconfig-interfaces:interfaces/interface[name=%s]", ifName) - - t.Run(tcPrefix+"ifName", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/name") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/name", portConfigNInfo(ifName, `{}`)) - }) - - t.Run(tcPrefix+"config_container", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/config") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/config", portConfigNInfo(ifName, `{"": `+portConfigFields+`}`)) - }) - - t.Run(tcPrefix+"config_attr", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/config/mtu") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/config/mtu", portConfigNInfo(ifName, `{"": {"mtu": ""}}`)) - }) - - t.Run(tcPrefix+"eth_all", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/openconfig-if-ethernet:ethernet") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/openconfig-if-ethernet:ethernet", - portConfigNInfo(ifName, `{"config":`+portEthConfigFields+`, "state":`+portEthConfigFields+`}`)) - }) - - t.Run(tcPrefix+"eth_config", func(t *testing.T) { - p := ifPath + "/openconfig-if-ethernet:ethernet/config" - tv := testTranslateSubscribe(t, p) - tv.VerifyCount(1, 0) - tv.VerifyTarget(p, portConfigNInfo(ifName, `{"":`+portEthConfigFields+`}`)) - }) - - t.Run(tcPrefix+"eth_speed", func(t *testing.T) { - p := ifPath + "/openconfig-if-ethernet:ethernet/state/port-speed" - tv := testTranslateSubscribe(t, p) - tv.VerifyCount(1, 0) - tv.VerifyTarget(p, portConfigNInfo(ifName, `{"":{"speed": ""}}`)) - }) - - t.Run(tcPrefix+"state_container", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/state") - tv.VerifyCount(1, 1) - tv.VerifyTarget(ifPath+"/state", portStateNInfo(ifName, portStateAllFields)) - tv.VerifyChild(ifPath+"/state/counters", portCountersNInfo(ifName)) - }) - - t.Run(tcPrefix+"state_admin_status", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/state/admin-status") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/state/admin-status", portStateNInfo(ifName, `{"": {"admin_status": ""}}`)) - }) - - t.Run(tcPrefix+"state_counters", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/state/counters") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/state/counters", portCountersNInfo(ifName)) - }) - - t.Run(tcPrefix+"state_counters_attr", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/state/counters/in-octets") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/state/counters/in-octets", portCountersNInfo(ifName)) - }) - - ipv4List := ifPath + "/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses/address" - ipv6List := ifPath + "/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses/address" - - for _, p := range []string{"/subinterfaces", "/subinterfaces/subinterface[index=*]", "/subinterfaces/subinterface[index=0]"} { - t.Run(tcPrefix+"subif="+NewPathInfo(p).Var("index"), func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+p) - tv.VerifyCount(2, 0) - tv.VerifyTarget(ipv4List+"[ip=*]", portIpAddrNInfo(ifName, portIpv4KeyPattern)) - tv.VerifyTarget(ipv6List+"[ip=*]", portIpAddrNInfo(ifName, portIpv6KeyPattern)) - }) - } - - t.Run(tcPrefix+"invalid_subif", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/subinterfaces/subinterface[index=2]") - tv.VerifyCount(translErr, 0) - }) - - for _, p := range []string{"", "/addresses", "/addresses/address[ip=*]"} { - t.Run(tcPrefix+"ipv4", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4"+p) - tv.VerifyCount(1, 0) - tv.VerifyTarget(ipv4List+"[ip=*]", portIpAddrNInfo(ifName, portIpv4KeyPattern)) - }) - } - - t.Run(tcPrefix+"ipv4_specific", func(t *testing.T) { - tv := testTranslateSubscribe(t, ipv4List+"[ip=1.2.3.4]") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ipv4List+"[ip=1.2.3.4]", portIpAddrNInfo(ifName, "1.2.3.4/*")) - }) - - t.Run(tcPrefix+"ipv4_invalid", func(t *testing.T) { - tv := testTranslateSubscribe(t, ipv4List+"[ip=1234]") - tv.VerifyCount(translErr, 0) - }) - - for _, p := range []string{"", "/addresses", "/addresses/address[ip=*]"} { - t.Run(tcPrefix+"ipv6", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6"+p) - tv.VerifyCount(1, 0) - tv.VerifyTarget(ipv6List+"[ip=*]", portIpAddrNInfo(ifName, portIpv6KeyPattern)) - }) - } - - t.Run(tcPrefix+"ipv6_specific", func(t *testing.T) { - tv := testTranslateSubscribe(t, ipv6List+"[ip=1001:80::1]") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ipv6List+"[ip=1001:80::1]", portIpAddrNInfo(ifName, "1001:80::1/*")) - }) - - t.Run(tcPrefix+"ipv6_invalid", func(t *testing.T) { - tv := testTranslateSubscribe(t, ipv6List+"[ip=1234abcd]") - tv.VerifyCount(translErr, 0) - }) - } -} - -const ( - portConfigFields = `{"description": "description", "admin_status": "enabled", "mtu": "mtu"}` - portEthConfigFields = `{"speed": "port-speed"}` - portStateAllFields = `{"": {"index": "ifindex", "admin_status": "enabled,admin-status", "oper_status": "oper-status", "description": "description", "mtu": "mtu"}}` - portConfigAllFields = `{"config": ` + portConfigFields + - `, "openconfig-if-ethernet:ethernet/config": ` + portEthConfigFields + - `, "openconfig-if-ethernet:ethernet/state": ` + portEthConfigFields + `}` - - portIpv4KeyPattern = "*.*.*.*/*" - portIpv6KeyPattern = "*:*/*" -) - -func portConfigNInfo(ifName, fieldsJson string) *notificationAppInfo { - return ¬ificationAppInfo{ - dbno: db.ConfigDB, - table: &db.TableSpec{Name: "PORT"}, - key: db.NewKey(ifName), - dbFldYgPathInfoList: parseFieldsJSON(fieldsJson), - isOnChangeSupported: true, - pType: OnChange, - } -} - -func portStateNInfo(ifName, fieldsJson string) *notificationAppInfo { - return ¬ificationAppInfo{ - dbno: db.ApplDB, - table: &db.TableSpec{Name: "PORT_TABLE"}, - key: db.NewKey(ifName), - dbFldYgPathInfoList: parseFieldsJSON(fieldsJson), - isOnChangeSupported: true, - pType: OnChange, - } -} - -func portCountersNInfo(ifName string) *notificationAppInfo { - fieldPattern := ifName - if ifName == "*" { - fieldPattern = countersMapFieldPattern - } - return ¬ificationAppInfo{ - dbno: db.CountersDB, - table: &db.TableSpec{Name: "COUNTERS_PORT_NAME_MAP"}, - key: db.NewKey(), - fieldScanPattern: fieldPattern, - isOnChangeSupported: false, - pType: Sample, - } -} - -func portIpAddrNInfo(ifName, ipAddr string) *notificationAppInfo { - return ¬ificationAppInfo{ - dbno: db.ConfigDB, - table: &db.TableSpec{Name: "INTERFACE"}, - key: db.NewKey(ifName, ipAddr), - isOnChangeSupported: true, - pType: OnChange, - } -} diff --git a/translib/sys_app.go b/translib/sys_app.go index 58b4b2f3c..a0a30a608 100644 --- a/translib/sys_app.go +++ b/translib/sys_app.go @@ -43,6 +43,13 @@ type SysApp struct { procTable map[uint64]dbEntry } +type reqType int + +type dbEntry struct { + op reqType + entry db.Value +} + func init() { log.Info("SysApp: Init called for System module") err := register("/openconfig-system:system", diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go new file mode 100644 index 000000000..b1807015c --- /dev/null +++ b/translib/transformer/xfmr_intf.go @@ -0,0 +1,1027 @@ +////////////////////////////////////////////////////////////////////////// +// +// 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 ( + "errors" + "github.com/Azure/sonic-mgmt-common/translib/db" + "github.com/Azure/sonic-mgmt-common/translib/ocbinds" + "github.com/Azure/sonic-mgmt-common/translib/tlerr" + log "github.com/golang/glog" + "github.com/openconfig/ygot/ygot" + "strconv" + "strings" +) + +func init() { + XlateFuncBind("intf_table_xfmr", intf_table_xfmr) + XlateFuncBind("YangToDb_intf_tbl_key_xfmr", YangToDb_intf_tbl_key_xfmr) + XlateFuncBind("DbToYang_intf_tbl_key_xfmr", DbToYang_intf_tbl_key_xfmr) + XlateFuncBind("YangToDb_intf_mtu_xfmr", YangToDb_intf_mtu_xfmr) + XlateFuncBind("DbToYang_intf_mtu_xfmr", DbToYang_intf_mtu_xfmr) + XlateFuncBind("DbToYang_intf_admin_status_xfmr", DbToYang_intf_admin_status_xfmr) + XlateFuncBind("YangToDb_intf_enabled_xfmr", YangToDb_intf_enabled_xfmr) + XlateFuncBind("DbToYang_intf_enabled_xfmr", DbToYang_intf_enabled_xfmr) + XlateFuncBind("YangToDb_intf_eth_port_config_xfmr", YangToDb_intf_eth_port_config_xfmr) + XlateFuncBind("DbToYang_intf_eth_port_config_xfmr", DbToYang_intf_eth_port_config_xfmr) + XlateFuncBind("DbToYangPath_intf_eth_port_config_path_xfmr", DbToYangPath_intf_eth_port_config_path_xfmr) + XlateFuncBind("DbToYang_intf_eth_auto_neg_xfmr", DbToYang_intf_eth_auto_neg_xfmr) + XlateFuncBind("DbToYang_intf_eth_port_speed_xfmr", DbToYang_intf_eth_port_speed_xfmr) +} + +const ( + PORT_ADMIN_STATUS = "admin_status" + PORTCHANNEL_TN = "PORTCHANNEL" + PORT_SPEED = "speed" + PORT_AUTONEG = "autoneg" + DEFAULT_MTU = "9100" +) + +const ( + PIPE = "|" + COLON = ":" + + ETHERNET = "Eth" + MGMT = "eth" + VLAN = "Vlan" + PORTCHANNEL = "PortChannel" + LOOPBACK = "Loopback" + VXLAN = "vtep" + MANAGEMENT = "Management" +) + +type TblData struct { + portTN string + memberTN string + intfTN string + keySep string +} + +type IntfTblData struct { + cfgDb TblData + appDb TblData + stateDb TblData +} + +var IntfTypeTblMap = map[E_InterfaceType]IntfTblData{ + IntfTypeEthernet: IntfTblData{ + cfgDb: TblData{portTN: "PORT", intfTN: "INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "PORT_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, + stateDb: TblData{portTN: "PORT_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, + }, + IntfTypeMgmt: IntfTblData{ + cfgDb: TblData{portTN: "MGMT_PORT", intfTN: "MGMT_INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "MGMT_PORT_TABLE", intfTN: "MGMT_INTF_TABLE", keySep: COLON}, + stateDb: TblData{portTN: "MGMT_PORT_TABLE", intfTN: "MGMT_INTERFACE_TABLE", keySep: PIPE}, + }, + IntfTypePortChannel: IntfTblData{ + cfgDb: TblData{portTN: "PORTCHANNEL", intfTN: "PORTCHANNEL_INTERFACE", memberTN: "PORTCHANNEL_MEMBER", keySep: PIPE}, + appDb: TblData{portTN: "LAG_TABLE", intfTN: "INTF_TABLE", keySep: COLON, memberTN: "LAG_MEMBER_TABLE"}, + stateDb: TblData{portTN: "LAG_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, + }, + IntfTypeVlan: IntfTblData{ + cfgDb: TblData{portTN: "VLAN", memberTN: "VLAN_MEMBER", intfTN: "VLAN_INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "VLAN_TABLE", memberTN: "VLAN_MEMBER_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, + }, + IntfTypeLoopback: IntfTblData{ + cfgDb: TblData{portTN: "LOOPBACK", intfTN: "LOOPBACK_INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "LOOPBACK_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, + }, + IntfTypeSubIntf: IntfTblData{ + cfgDb: TblData{portTN: "VLAN_SUB_INTERFACE", intfTN: "VLAN_SUB_INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "PORT_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, + stateDb: TblData{portTN: "PORT_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, + }, +} + +var dbIdToTblMap = map[db.DBNum][]string{ + db.ConfigDB: {"PORT", "MGMT_PORT", "VLAN", "PORTCHANNEL", "LOOPBACK", "VXLAN_TUNNEL", "VLAN_SUB_INTERFACE"}, + db.ApplDB: {"PORT_TABLE", "MGMT_PORT_TABLE", "VLAN_TABLE", "LAG_TABLE"}, + db.StateDB: {"PORT_TABLE", "MGMT_PORT_TABLE", "LAG_TABLE"}, +} + +var intfOCToSpeedMap = map[ocbinds.E_OpenconfigIfEthernet_ETHERNET_SPEED]string{ + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_10MB: "10", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_100MB: "100", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_1GB: "1000", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_2500MB: "2500", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_5GB: "5000", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_10GB: "10000", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_25GB: "25000", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_40GB: "40000", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_50GB: "50000", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_100GB: "100000", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_200GB: "200000", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_400GB: "400000", +} + +type E_InterfaceType int64 + +const ( + IntfTypeUnset E_InterfaceType = 0 + IntfTypeEthernet E_InterfaceType = 1 + IntfTypeMgmt E_InterfaceType = 2 + IntfTypeVlan E_InterfaceType = 3 + IntfTypePortChannel E_InterfaceType = 4 + IntfTypeLoopback E_InterfaceType = 5 + IntfTypeVxlan E_InterfaceType = 6 + IntfTypeSubIntf E_InterfaceType = 7 +) + +type E_InterfaceSubType int64 + +const ( + IntfSubTypeUnset E_InterfaceSubType = 0 + IntfSubTypeVlanL2 E_InterfaceSubType = 1 + InterfaceSubTypeVlanL3 E_InterfaceSubType = 2 +) + +func getIntfTypeByName(name string) (E_InterfaceType, E_InterfaceSubType, error) { + + var err error + if strings.Contains(name, ".") { + if strings.HasPrefix(name, ETHERNET) || strings.HasPrefix(name, "Po") { + return IntfTypeSubIntf, IntfSubTypeUnset, err + } + } + if strings.HasPrefix(name, ETHERNET) { + return IntfTypeEthernet, IntfSubTypeUnset, err + } else { + err = errors.New("Interface name prefix not matched with supported types") + return IntfTypeUnset, IntfSubTypeUnset, err + } +} + +func getIntfsRoot(s *ygot.GoStruct) *ocbinds.OpenconfigInterfaces_Interfaces { + deviceObj := (*s).(*ocbinds.Device) + return deviceObj.Interfaces +} + +func getPortTableNameByDBId(intftbl IntfTblData, curDb db.DBNum) (string, error) { + + var tblName string + + switch curDb { + case db.ConfigDB: + tblName = intftbl.cfgDb.portTN + case db.ApplDB: + tblName = intftbl.appDb.portTN + case db.StateDB: + tblName = intftbl.stateDb.portTN + default: + tblName = intftbl.cfgDb.portTN + } + + return tblName, nil +} + +/* Perform action based on the operation and Interface type wrt Interface name key */ +/* It should handle only Interface name key xfmr operations */ +func performIfNameKeyXfmrOp(inParams *XfmrParams, requestUriPath *string, ifName *string, ifType E_InterfaceType, subintfid uint32) error { + var err error + switch inParams.oper { + case GET: + if ifType == IntfTypeSubIntf && subintfid == 0 { + errStr := "Invalid interface name: " + *ifName + log.Infof("Invalid interface name: %s for GET path: %v", *ifName, *requestUriPath) + err = tlerr.InvalidArgsError{Format: errStr} + return err + } + case DELETE: + if *requestUriPath == "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface" && subintfid != 0 { + return nil + } + + if *requestUriPath == "/openconfig-interfaces:interfaces/interface" { + switch ifType { + case IntfTypeEthernet: + err = validateIntfExists(inParams.d, IntfTypeTblMap[IntfTypeEthernet].cfgDb.portTN, *ifName) + if err != nil { + // Not returning error from here since mgmt infra will return "Resource not found" error in case of non existence entries + return nil + } + errStr := "Physical Interface: " + *ifName + " cannot be deleted" + err = tlerr.InvalidArgsError{Format: errStr} + return err + default: + errStr := "Invalid interface for delete:" + *ifName + log.Error(errStr) + return tlerr.InvalidArgsError{Format: errStr} + } + + } + case CREATE: + fallthrough + case UPDATE, REPLACE: + if ifType == IntfTypeEthernet { + err = validateIntfExists(inParams.d, IntfTypeTblMap[IntfTypeEthernet].cfgDb.portTN, *ifName) + if err != nil { // Invalid Physical interface + errStr := "Interface " + *ifName + " cannot be configured." + return tlerr.InvalidArgsError{Format: errStr} + } + if inParams.oper == REPLACE { + if strings.Contains(*requestUriPath, "/openconfig-interfaces:interfaces/interface") { + if strings.Contains(*requestUriPath, "openconfig-if-ethernet:ethernet/openconfig-vlan:switched-vlan") || + strings.Contains(*requestUriPath, "mapped-vlans") { + log.Infof("allow replace operation for switched-vlan") + } else { + // OC interfaces yang does not have attributes to set Physical interface critical attributes like speed, alias, lanes, index. + // Replace/PUT request without the critical attributes would end up in deletion of the same in PORT table, which cannot be allowed. + // Hence block the Replace/PUT request for Physical interfaces alone. + err_str := "Replace/PUT request not allowed for Physical interfaces" + return tlerr.NotSupported(err_str) + } + } + } + } + } + return err +} + +/* Validate whether intf exists in DB */ +func validateIntfExists(d *db.DB, intfTs string, ifName string) error { + if len(ifName) == 0 { + return errors.New("Length of Interface name is zero") + } + + entry, err := d.GetEntry(&db.TableSpec{Name: intfTs}, db.Key{Comp: []string{ifName}}) + if err != nil || !entry.IsPopulated() { + errStr := "Invalid Interface:" + ifName + if log.V(3) { + log.Error(errStr) + } + return tlerr.InvalidArgsError{Format: errStr} + } + return nil +} + +func getMemTableNameByDBId(intftbl IntfTblData, curDb db.DBNum) (string, error) { + + var tblName string + + switch curDb { + case db.ConfigDB: + tblName = intftbl.cfgDb.memberTN + case db.ApplDB: + tblName = intftbl.appDb.memberTN + case db.StateDB: + tblName = intftbl.stateDb.memberTN + default: + tblName = intftbl.cfgDb.memberTN + } + + return tblName, nil +} + +func retrievePortChannelAssociatedWithIntf(inParams *XfmrParams, ifName *string) (*string, error) { + var err error + + if strings.HasPrefix(*ifName, ETHERNET) { + intTbl := IntfTypeTblMap[IntfTypePortChannel] + tblName, _ := getMemTableNameByDBId(intTbl, inParams.curDb) + var lagStr string + + lagKeys, err := inParams.d.GetKeysByPattern(&db.TableSpec{Name: tblName}, "*"+*ifName) + /* Find the port-channel the given ifname is part of */ + if err != nil { + return nil, err + } + var flag bool = false + for i := range lagKeys { + if *ifName == lagKeys[i].Get(1) { + flag = true + lagStr = lagKeys[i].Get(0) + log.Info("Given interface part of PortChannel: ", lagStr) + break + } + } + if !flag { + log.Info("Given Interface not part of any PortChannel") + return nil, err + } + return &lagStr, err + } + return nil, err +} + +func updateDefaultMtu(inParams *XfmrParams, ifName *string, ifType E_InterfaceType, resMap map[string]string) error { + var err error + subOpMap := make(map[db.DBNum]map[string]map[string]db.Value) + intfMap := make(map[string]map[string]db.Value) + + intTbl := IntfTypeTblMap[ifType] + resMap["mtu"] = DEFAULT_MTU + + intfMap[intTbl.cfgDb.portTN] = make(map[string]db.Value) + intfMap[intTbl.cfgDb.portTN][*ifName] = db.Value{Field: resMap} + + subOpMap[db.ConfigDB] = intfMap + inParams.subOpDataMap[UPDATE] = &subOpMap + return err +} + +func getDbToYangSpeed(speed string) (ocbinds.E_OpenconfigIfEthernet_ETHERNET_SPEED, error) { + portSpeed := ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN + var err error = errors.New("Not found in port speed map") + for k, v := range intfOCToSpeedMap { + if speed == v { + portSpeed = k + err = nil + } + } + return portSpeed, err +} + +var intf_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string, error) { + var tblList []string + var err error + + pathInfo := NewPathInfo(inParams.uri) + targetUriPath := pathInfo.YangPath + targetUriXpath, _, _ := XfmrRemoveXPATHPredicates(targetUriPath) + + ifName := pathInfo.Var("name") + if ifName == "" { + log.Info("TableXfmrFunc - intf_table_xfmr Intf key is not present") + + if _, ok := dbIdToTblMap[inParams.curDb]; !ok { + if log.V(3) { + log.Info("TableXfmrFunc - intf_table_xfmr db id entry not present") + } + return tblList, errors.New("Key not present") + } else { + return dbIdToTblMap[inParams.curDb], nil + } + } + + idx := pathInfo.Var("index") + var i32 uint32 + i32 = 0 + if idx != "" { + i64, _ := strconv.ParseUint(idx, 10, 32) + i32 = uint32(i64) + } + + intfType, _, ierr := getIntfTypeByName(ifName) + if intfType == IntfTypeUnset || ierr != nil { + return tblList, errors.New("Invalid interface type IntfTypeUnset") + } + intTbl := IntfTypeTblMap[intfType] + if log.V(3) { + log.Info("TableXfmrFunc - targetUriPath : ", targetUriPath) + log.Info("TableXfmrFunc - targetUriXpath : ", targetUriXpath) + } + + if inParams.oper == DELETE && (targetUriXpath == "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4" || + targetUriXpath == "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6") { + errStr := "DELETE operation not allowed on this container" + return tblList, tlerr.NotSupportedError{Path: "", Format: errStr} + + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/config") { + tblList = append(tblList, intTbl.cfgDb.portTN) + } else if intfType != IntfTypeEthernet && intfType != IntfTypeMgmt && + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet") { + //Checking interface type at container level, if not Ethernet type return nil + return nil, nil + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/ethernet/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/state") { + tblList = append(tblList, intTbl.appDb.portTN) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/config") { + if i32 > 0 { + tblList = append(tblList, "VLAN_SUB_INTERFACE") + } else { + tblList = append(tblList, intTbl.cfgDb.intfTN) + } + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/state") { + tblList = append(tblList, intTbl.appDb.intfTN) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses") { + tblList = append(tblList, intTbl.cfgDb.intfTN) + } else if inParams.oper == GET && strings.HasPrefix(targetUriXpath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/neighbors") || + strings.HasPrefix(targetUriXpath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/neighbors") { + tblList = append(tblList, "NONE") + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/ethernet") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet") { + if inParams.oper != DELETE { + tblList = append(tblList, intTbl.cfgDb.portTN) + } + } else if targetUriPath == "/openconfig-interfaces:interfaces/interface" { + tblList = append(tblList, intTbl.cfgDb.portTN) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface") { + if inParams.oper != DELETE { + tblList = append(tblList, intTbl.cfgDb.portTN) + } + } else { + err = errors.New("Invalid URI") + } + + if log.V(3) { + log.Infof("TableXfmrFunc - Uri: (%v), targetUriPath: %s, tblList: (%v)", inParams.uri, targetUriPath, tblList) + } + + return tblList, err +} + +var YangToDb_intf_tbl_key_xfmr KeyXfmrYangToDb = func(inParams XfmrParams) (string, error) { + var err error + + pathInfo := NewPathInfo(inParams.uri) + reqpathInfo := NewPathInfo(inParams.requestUri) + requestUriPath := reqpathInfo.YangPath + + log.Infof("YangToDb_intf_tbl_key_xfmr: inParams.uri: %s, pathInfo: %s, inParams.requestUri: %s", inParams.uri, pathInfo, requestUriPath) + + ifName := pathInfo.Var("name") + idx := reqpathInfo.Var("index") + var i32 uint32 + i32 = 0 + + if idx != "" { + i64, _ := strconv.ParseUint(idx, 10, 32) + i32 = uint32(i64) + } + + if ifName == "*" { + return ifName, nil + } + + if ifName != "" { + log.Info("YangToDb_intf_tbl_key_xfmr: ifName: ", ifName) + intfType, _, ierr := getIntfTypeByName(ifName) + if ierr != nil { + log.Errorf("Extracting Interface type for Interface: %s failed!", ifName) + return "", tlerr.New(ierr.Error()) + } + err = performIfNameKeyXfmrOp(&inParams, &requestUriPath, &ifName, intfType, i32) + if err != nil { + return "", tlerr.InvalidArgsError{Format: err.Error()} + } + } + return ifName, err +} + +var DbToYang_intf_tbl_key_xfmr KeyXfmrDbToYang = func(inParams XfmrParams) (map[string]interface{}, error) { + /* Code for DBToYang - Key xfmr. */ + if log.V(3) { + log.Info("Entering DbToYang_intf_tbl_key_xfmr") + } + res_map := make(map[string]interface{}) + log.Info("DbToYang_intf_tbl_key_xfmr: Interface Name = ", inParams.key) + res_map["name"] = inParams.key + return res_map, nil +} + +var YangToDb_intf_mtu_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[string]string, error) { + res_map := make(map[string]string) + var ifName string + intfsObj := getIntfsRoot(inParams.ygRoot) + if intfsObj == nil || len(intfsObj.Interface) < 1 { + return res_map, nil + } else { + for infK := range intfsObj.Interface { + ifName = infK + } + } + intfType, _, _ := getIntfTypeByName(ifName) + if IntfTypeVxlan == intfType { + return res_map, nil + } + if inParams.oper == DELETE { + log.Infof("Updating the Interface: %s with default MTU", ifName) + if intfType == IntfTypeLoopback { + log.Infof("MTU not supported for Loopback Interface Type: %d", intfType) + return res_map, nil + } + /* Note: For the mtu delete request, res_map with delete operation and + subOp map with update operation (default MTU value) is filled. This is because, transformer default + updates the result DS for delete oper with table and key. This needs to be fixed by transformer + for deletion of an attribute */ + err := updateDefaultMtu(&inParams, &ifName, intfType, res_map) + if err != nil { + log.Errorf("Updating Default MTU for Interface: %s failed", ifName) + return res_map, err + } + return res_map, nil + } + // Handles all the operations other than Delete + intfTypeVal, _ := inParams.param.(*uint16) + intTypeValStr := strconv.FormatUint(uint64(*intfTypeVal), 10) + + if IntfTypePortChannel == intfType { + /* Apply the MTU to all the portchannel member ports */ + //updateMemberPortsMtu(&inParams, &ifName, &intTypeValStr) + } else if IntfTypeEthernet == intfType { + /* Do not allow MTU configuration on a portchannel member port */ + lagId, _ := retrievePortChannelAssociatedWithIntf(&inParams, &ifName) + if lagId != nil { + log.Infof("%s is member of %s", ifName, *lagId) + errStr := "Configuration not allowed when port is member of Portchannel." + return nil, tlerr.InvalidArgsError{Format: errStr} + } + } + + res_map["mtu"] = intTypeValStr + return res_map, nil +} + +var DbToYang_intf_mtu_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + + data := (*inParams.dbDataMap)[inParams.curDb] + + intfType, _, ierr := getIntfTypeByName(inParams.key) + if intfType == IntfTypeUnset || ierr != nil { + log.Info("DbToYang_intf_mtu_xfmr - Invalid interface type IntfTypeUnset") + return result, errors.New("Invalid interface type IntfTypeUnset") + } + if IntfTypeVxlan == intfType { + return result, nil + } + intTbl := IntfTypeTblMap[intfType] + + tblName, _ := getPortTableNameByDBId(intTbl, inParams.curDb) + if _, ok := data[tblName]; !ok { + log.Info("DbToYang_intf_mtu_xfmr table not found : ", tblName) + return result, errors.New("table not found : " + tblName) + } + + pTbl := data[tblName] + if _, ok := pTbl[inParams.key]; !ok { + log.Info("DbToYang_intf_mtu_xfmr Interface not found : ", inParams.key) + return result, errors.New("Interface not found : " + inParams.key) + } + prtInst := pTbl[inParams.key] + mtuStr, ok := prtInst.Field["mtu"] + if ok { + mtuVal, err := strconv.ParseUint(mtuStr, 10, 16) + if err != nil { + return result, err + } + result["mtu"] = mtuVal + } + return result, err +} + +// YangToDb_intf_eth_port_config_xfmr handles port-speed, unreliable-los, auto-neg and aggregate-id config. +var YangToDb_intf_eth_port_config_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) (map[string]map[string]db.Value, error) { + var err error + var lagStr string + memMap := make(map[string]map[string]db.Value) + + pathInfo := NewPathInfo(inParams.uri) + requestUriPath := (NewPathInfo(inParams.requestUri)).YangPath + uriIfName := pathInfo.Var("name") + ifName := uriIfName + + intfType, _, err := getIntfTypeByName(ifName) + if err != nil { + errStr := "Invalid Interface" + err = tlerr.InvalidArgsError{Format: errStr} + return nil, err + } + if IntfTypeVxlan == intfType || IntfTypeVlan == intfType { + return memMap, nil + } + + intfsObj := getIntfsRoot(inParams.ygRoot) + intfObj := intfsObj.Interface[uriIfName] + + // Need to differentiate between config container delete and any attribute other than aggregate-id delete + if inParams.oper == DELETE { + /* Handles 3 cases + case 1: Deletion request at top-level container / list + case 2: Deletion request at ethernet container level + case 3: Deletion request at ethernet/config container level */ + + //case 1 + if intfObj.Ethernet == nil || + //case 2 + intfObj.Ethernet.Config == nil || + //case 3 + (intfObj.Ethernet.Config != nil && requestUriPath == "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config") { + + // Delete all the Vlans for Interface and member port removal from port-channel + lagId, err := retrievePortChannelAssociatedWithIntf(&inParams, &ifName) + if lagId != nil { + log.Infof("%s is member of %s", ifName, *lagId) + } + if err != nil { + errStr := "Retrieveing PortChannel associated with Interface: " + ifName + " failed!" + return nil, errors.New(errStr) + } + if lagId != nil { + lagStr = *lagId + intTbl := IntfTypeTblMap[IntfTypePortChannel] + tblName, _ := getMemTableNameByDBId(intTbl, inParams.curDb) + + m := make(map[string]string) + value := db.Value{Field: m} + m["NULL"] = "NULL" + intfKey := lagStr + "|" + ifName + if _, ok := memMap[tblName]; !ok { + memMap[tblName] = make(map[string]db.Value) + } + memMap[tblName][intfKey] = value + } + return memMap, err + } + } + + /* Handle PortSpeed config */ + if intfObj.Ethernet.Config.PortSpeed != 0 { + res_map := make(map[string]string) + value := db.Value{Field: res_map} + intTbl := IntfTypeTblMap[intfType] + + portSpeed := intfObj.Ethernet.Config.PortSpeed + val, ok := intfOCToSpeedMap[portSpeed] + if ok { + err = nil + res_map[PORT_SPEED] = val + if IntfTypeMgmt != intfType { + res_map[PORT_AUTONEG] = "off" + } + } else { + err = tlerr.InvalidArgs("Invalid speed %s", val) + } + + if err == nil { + if _, ok := memMap[intTbl.cfgDb.portTN]; !ok { + memMap[intTbl.cfgDb.portTN] = make(map[string]db.Value) + } + memMap[intTbl.cfgDb.portTN][ifName] = value + } + } else if requestUriPath == "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config/port-speed" { + if inParams.oper == DELETE { + err_str := "DELETE request not allowed for port-speed" + return nil, tlerr.NotSupported(err_str) + } else { + log.Error("Unexpected oper ", inParams.oper) + } + } + + /* Prepare the map to handle multiple entries */ + res_map := make(map[string]string) + value := db.Value{Field: res_map} + + /* Handle AutoNegotiate config */ + if intfObj.Ethernet.Config.AutoNegotiate != nil { + if intfType == IntfTypeMgmt || intfType == IntfTypeEthernet { + intTbl := IntfTypeTblMap[intfType] + autoNeg := intfObj.Ethernet.Config.AutoNegotiate + var enStr string + if *autoNeg { + if IntfTypeMgmt == intfType { + enStr = "true" + } else { + enStr = "on" + } + } else { + if IntfTypeMgmt == intfType { + enStr = "false" + } else { + enStr = "off" + } + } + res_map[PORT_AUTONEG] = enStr + + if _, ok := memMap[intTbl.cfgDb.portTN]; !ok { + memMap[intTbl.cfgDb.portTN] = make(map[string]db.Value) + } + memMap[intTbl.cfgDb.portTN][ifName] = value + } else { + return nil, errors.New("AutoNegotiate config not supported for given Interface type") + } + } + + return memMap, err +} + +// DbToYang_intf_eth_port_config_xfmr is to handle DB to yang translation of port-speed, auto-neg and aggregate-id config. +var DbToYang_intf_eth_port_config_xfmr SubTreeXfmrDbToYang = func(inParams XfmrParams) error { + var err error + intfsObj := getIntfsRoot(inParams.ygRoot) + pathInfo := NewPathInfo(inParams.uri) + uriIfName := pathInfo.Var("name") + ifName := uriIfName + + intfType, _, err := getIntfTypeByName(ifName) + if err != nil { + errStr := "Invalid Interface" + err = tlerr.InvalidArgsError{Format: errStr} + return err + } + if IntfTypeVxlan == intfType { + return nil + } + intTbl := IntfTypeTblMap[intfType] + tblName := intTbl.cfgDb.portTN + entry, dbErr := inParams.dbs[db.ConfigDB].GetEntry(&db.TableSpec{Name: tblName}, db.Key{Comp: []string{ifName}}) + if dbErr != nil { + errStr := "Invalid Interface" + err = tlerr.InvalidArgsError{Format: errStr} + return err + } + targetUriPath := pathInfo.YangPath + if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config") { + get_cfg_obj := false + var intfObj *ocbinds.OpenconfigInterfaces_Interfaces_Interface + if intfsObj != nil && intfsObj.Interface != nil && len(intfsObj.Interface) > 0 { + var ok bool = false + if intfObj, ok = intfsObj.Interface[uriIfName]; !ok { + intfObj, _ = intfsObj.NewInterface(uriIfName) + } + ygot.BuildEmptyTree(intfObj) + } else { + ygot.BuildEmptyTree(intfsObj) + intfObj, _ = intfsObj.NewInterface(uriIfName) + ygot.BuildEmptyTree(intfObj) + } + ygot.BuildEmptyTree(intfObj.Ethernet) + ygot.BuildEmptyTree(intfObj.Ethernet.Config) + + if targetUriPath == "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config" { + get_cfg_obj = true + } + var errStr string + if get_cfg_obj { + is_id_populated := false + + if !is_id_populated { + errStr = "aggregate-id not set" + } + + // subscribe for aggregate-id needs "Resource not found" for delete notification + if (targetUriPath == "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config/openconfig-if-aggregate:aggregate-id") && (!is_id_populated) { + err = tlerr.NotFoundError{Format: "Resource not found"} + return err + } + } + + if entry.IsPopulated() { + if get_cfg_obj || targetUriPath == "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config/auto-negotiate" { + autoNeg, ok := entry.Field[PORT_AUTONEG] + if ok { + var oc_auto_neg bool + if autoNeg == "on" || autoNeg == "true" { + oc_auto_neg = true + } else { + oc_auto_neg = false + } + intfObj.Ethernet.Config.AutoNegotiate = &oc_auto_neg + } else { + errStr = "auto-negotiate not set" + } + } + if get_cfg_obj || targetUriPath == "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config/port-speed" { + speed, ok := entry.Field[PORT_SPEED] + portSpeed := ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_UNSET + if ok { + portSpeed, err = getDbToYangSpeed(speed) + intfObj.Ethernet.Config.PortSpeed = portSpeed + } else { + errStr = "port-speed not set" + } + } + + } else { + errStr = "Attribute not set" + } + if !get_cfg_obj && errStr != "" { + err = tlerr.InvalidArgsError{Format: errStr} + } + } + + return err +} + +var DbToYangPath_intf_eth_port_config_path_xfmr PathXfmrDbToYangFunc = func(params XfmrDbToYgPathParams) error { + log.Info("DbToYangPath_intf_eth_port_config_path_xfmr: params: ", params) + + intfRoot := "/openconfig-interfaces:interfaces/interface" + + if (params.tblName != "PORT") && (params.tblName != "PORTCHANNEL_MEMBER") && + (params.tblName != "MGMT_PORT") { + log.Info("DbToYangPath_intf_eth_port_config_path_xfmr: from wrong table: ", params.tblName) + return nil + } + + if (params.tblName == "PORT") && (len(params.tblKeyComp) > 0) { + params.ygPathKeys[intfRoot+"/name"] = params.tblKeyComp[0] + } else if (params.tblName == "PORTCHANNEL_MEMBER") && (len(params.tblKeyComp) > 1) { + params.ygPathKeys[intfRoot+"/name"] = params.tblKeyComp[1] + } else if (params.tblName == "MGMT_PORT") && (len(params.tblKeyComp) > 0) { + params.ygPathKeys[intfRoot+"/name"] = params.tblKeyComp[0] + } else { + log.Info("DbToYangPath_intf_eth_port_config_path_xfmr, wrong param: tbl ", params.tblName, " key ", params.tblKeyComp) + return nil + } + + log.Info("DbToYangPath_intf_eth_port_config_path_xfmr: params.ygPathkeys: ", params.ygPathKeys) + + return nil +} + +var DbToYang_intf_eth_auto_neg_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + + data := (*inParams.dbDataMap)[inParams.curDb] + intfType, _, ierr := getIntfTypeByName(inParams.key) + if intfType == IntfTypeUnset || ierr != nil { + log.Info("DbToYang_intf_eth_auto_neg_xfmr - Invalid interface type IntfTypeUnset") + return result, errors.New("Invalid interface type IntfTypeUnset") + } + if IntfTypeMgmt != intfType && IntfTypeEthernet != intfType { + return result, nil + } + intTbl := IntfTypeTblMap[intfType] + + tblName, _ := getPortTableNameByDBId(intTbl, inParams.curDb) + pTbl := data[tblName] + prtInst := pTbl[inParams.key] + autoNeg, ok := prtInst.Field[PORT_AUTONEG] + if ok { + if autoNeg == "on" || autoNeg == "true" { + result["auto-negotiate"] = true + } else { + result["auto-negotiate"] = false + } + } else { + log.Info("auto-negotiate field not found in DB") + } + return result, err +} + +var DbToYang_intf_eth_port_speed_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + + data := (*inParams.dbDataMap)[inParams.curDb] + intfType, _, ierr := getIntfTypeByName(inParams.key) + if intfType == IntfTypeUnset || ierr != nil { + log.Info("DbToYang_intf_eth_port_speed_xfmr - Invalid interface type IntfTypeUnset") + return result, errors.New("Invalid interface type IntfTypeUnset") + } + if IntfTypeVxlan == intfType || IntfTypeVlan == intfType { + return result, nil + } + + intTbl := IntfTypeTblMap[intfType] + + tblName, _ := getPortTableNameByDBId(intTbl, inParams.curDb) + pTbl := data[tblName] + prtInst := pTbl[inParams.key] + speed, ok := prtInst.Field[PORT_SPEED] + portSpeed := ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_UNSET + if ok { + portSpeed, err = getDbToYangSpeed(speed) + result["port-speed"] = ocbinds.E_OpenconfigIfEthernet_ETHERNET_SPEED.ΛMap(portSpeed)["E_OpenconfigIfEthernet_ETHERNET_SPEED"][int64(portSpeed)].Name + } else { + log.Info("Speed field not found in DB") + } + + return result, err +} + +var DbToYang_intf_admin_status_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + + data := (*inParams.dbDataMap)[inParams.curDb] + + intfType, _, ierr := getIntfTypeByName(inParams.key) + if intfType == IntfTypeUnset || ierr != nil { + log.Info("DbToYang_intf_admin_status_xfmr - Invalid interface type IntfTypeUnset") + return result, errors.New("Invalid interface type IntfTypeUnset") + } + if IntfTypeVxlan == intfType { + return result, nil + } + intTbl := IntfTypeTblMap[intfType] + + tblName, _ := getPortTableNameByDBId(intTbl, inParams.curDb) + if _, ok := data[tblName]; !ok { + log.Info("DbToYang_intf_admin_status_xfmr table not found : ", tblName) + return result, errors.New("table not found : " + tblName) + } + pTbl := data[tblName] + if _, ok := pTbl[inParams.key]; !ok { + log.Info("DbToYang_intf_admin_status_xfmr Interface not found : ", inParams.key) + return result, errors.New("Interface not found : " + inParams.key) + } + prtInst := pTbl[inParams.key] + adminStatus, ok := prtInst.Field[PORT_ADMIN_STATUS] + var status ocbinds.E_OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus + if ok { + if adminStatus == "up" { + status = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UP + } else { + status = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_DOWN + } + result["admin-status"] = ocbinds.E_OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus.ΛMap(status)["E_OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus"][int64(status)].Name + } else { + log.Info("Admin status field not found in DB") + } + + return result, err +} + +var YangToDb_intf_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[string]string, error) { + res_map := make(map[string]string) + var ifName string + intfsObj := getIntfsRoot(inParams.ygRoot) + if intfsObj == nil || len(intfsObj.Interface) < 1 { + return res_map, nil + } else { + for infK := range intfsObj.Interface { + ifName = infK + } + } + intfType, _, _ := getIntfTypeByName(ifName) + if IntfTypeVxlan == intfType { + return res_map, nil + } + enabled, _ := inParams.param.(*bool) + var enStr string + if *enabled { + enStr = "up" + } else { + enStr = "down" + } + res_map[PORT_ADMIN_STATUS] = enStr + + return res_map, nil +} + +var DbToYang_intf_enabled_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + + data := (*inParams.dbDataMap)[inParams.curDb] + + intfType, _, ierr := getIntfTypeByName(inParams.key) + if intfType == IntfTypeUnset || ierr != nil { + log.Info("DbToYang_intf_enabled_xfmr - Invalid interface type IntfTypeUnset") + return result, errors.New("Invalid interface type IntfTypeUnset") + } + if IntfTypeVxlan == intfType { + return result, nil + } + + intTbl := IntfTypeTblMap[intfType] + + tblName, _ := getPortTableNameByDBId(intTbl, inParams.curDb) + if _, ok := data[tblName]; !ok { + log.Info("DbToYang_intf_enabled_xfmr table not found : ", tblName) + return result, errors.New("table not found : " + tblName) + } + + pTbl := data[tblName] + if _, ok := pTbl[inParams.key]; !ok { + log.Info("DbToYang_intf_enabled_xfmr Interface not found : ", inParams.key) + return result, errors.New("Interface not found : " + inParams.key) + } + prtInst := pTbl[inParams.key] + adminStatus, ok := prtInst.Field[PORT_ADMIN_STATUS] + if ok { + if adminStatus == "up" { + result["enabled"] = true + } else { + result["enabled"] = false + } + } else { + log.Info("Admin status field not found in DB") + } + return result, err +} From 04b70766f1d2f092d7473ae329d6e435fe912da3 Mon Sep 17 00:00:00 2001 From: Nikita Agarwal Date: Tue, 6 Feb 2024 11:28:14 -0800 Subject: [PATCH 02/13] Adding support for OC yang intf. --- config/transformer/models_list | 4 + .../openconfig-interfaces-annot.yang | 140 + .../openconfig-interfaces-deviation.yang | 135 + models/yang/openconfig-if-ip.yang | 9 + models/yang/sonic/import.mk | 4 +- translib/intf_app.go | 1405 ---------- translib/intf_app_test.go | 240 -- translib/sys_app.go | 7 + translib/transformer/xfmr_intf.go | 2271 +++++++++++++++++ translib/utils/utils.go | 6 + 10 files changed, 2575 insertions(+), 1646 deletions(-) create mode 100644 models/yang/annotations/openconfig-interfaces-annot.yang create mode 100644 models/yang/extensions/openconfig-interfaces-deviation.yang delete mode 100644 translib/intf_app.go delete mode 100644 translib/intf_app_test.go create mode 100644 translib/transformer/xfmr_intf.go diff --git a/config/transformer/models_list b/config/transformer/models_list index 1789f52c9..ba3f12d0a 100644 --- a/config/transformer/models_list +++ b/config/transformer/models_list @@ -3,3 +3,7 @@ openconfig-acl.yang openconfig-acl-annot.yang openconfig-sampling-sflow.yang openconfig-sampling-sflow-annot.yang +openconfig-if-ethernet.yang +openconfig-interfaces.yang +openconfig-interfaces-annot.yang +openconfig-if-ip.yang diff --git a/models/yang/annotations/openconfig-interfaces-annot.yang b/models/yang/annotations/openconfig-interfaces-annot.yang new file mode 100644 index 000000000..d23b1038f --- /dev/null +++ b/models/yang/annotations/openconfig-interfaces-annot.yang @@ -0,0 +1,140 @@ +module openconfig-interfaces-annot { + + yang-version "1"; + + namespace "http://openconfig.net/yang/annotation/openconfig-interfaces-annot"; + prefix "oc-interfaces-annot"; + + import sonic-extensions { prefix sonic-ext; } + import openconfig-interfaces { prefix oc-intf; } + import openconfig-if-ip {prefix oc-ip; } + + deviation /oc-intf:interfaces/oc-intf:interface { + deviate add { + sonic-ext:key-transformer "intf_tbl_key_xfmr"; + sonic-ext:table-transformer "intf_table_xfmr"; + } + } + + deviation /oc-intf:interfaces { + deviate add { + sonic-ext:pre-transformer "intf_pre_xfmr"; + sonic-ext:post-transformer "intf_post_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state { + deviate add { + sonic-ext:db-name "APPL_DB"; + } + } + + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:admin-status { + deviate add { + sonic-ext:field-transformer "intf_admin_status_xfmr"; + sonic-ext:field-name "admin_status"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-intf:enabled { + deviate add { + sonic-ext:field-transformer "intf_enabled_xfmr"; + sonic-ext:field-name "admin_status"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:enabled { + deviate add { + sonic-ext:field-transformer "intf_enabled_xfmr"; + sonic-ext:field-name "admin_status"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces { + deviate add { + sonic-ext:table-name "NONE"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface { + deviate add { + sonic-ext:table-transformer "intf_subintfs_table_xfmr"; + sonic-ext:virtual-table "true"; + sonic-ext:key-transformer "intf_subintfs_xfmr"; + sonic-ext:path-transformer "intf_ip_path_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-intf:config/oc-intf:index { + deviate add { + sonic-ext:field-transformer "subif_index_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-intf:state/oc-intf:index { + deviate add { + sonic-ext:field-transformer "subif_index_xfmr"; + } + } + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4/oc-ip:addresses { + deviate add { + sonic-ext:table-name "NONE"; + sonic-ext:subtree-transformer "intf_ip_addr_xfmr"; + } + } + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:addresses { + deviate add { + sonic-ext:table-name "NONE"; + sonic-ext:subtree-transformer "intf_ip_addr_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4/oc-ip:addresses/oc-ip:address { + deviate add { + sonic-ext:key-transformer "subintf_ip_addr_key_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:addresses/oc-ip:address { + deviate add { + sonic-ext:key-transformer "subintf_ip_addr_key_xfmr"; + } + } + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4 { + deviate add { + sonic-ext:table-transformer "intf_table_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6 { + deviate add { + sonic-ext:key-transformer "subintf_ipv6_tbl_key_xfmr"; + sonic-ext:table-transformer "intf_table_xfmr"; + } + } + deviation /oc-intf:interfaces/oc-intf:interface/oc-vlan:routed-vlan/oc-ip:ipv6/oc-ip:config/oc-ip:enabled { + deviate add { + sonic-ext:field-transformer "ipv6_enabled_xfmr"; + sonic-ext:field-name "ipv6_use_link_local_only"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-vlan:routed-vlan/oc-ip:ipv6/oc-ip:state/oc-ip:enabled { + deviate add { + sonic-ext:field-transformer "ipv6_enabled_xfmr"; + sonic-ext:field-name "ipv6_use_link_local_only"; + } + } + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:config/oc-ip:enabled { + deviate add { + sonic-ext:field-transformer "ipv6_enabled_xfmr"; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:state/oc-ip:enabled { + deviate add { + sonic-ext:field-transformer "ipv6_enabled_xfmr"; + } + } +} diff --git a/models/yang/extensions/openconfig-interfaces-deviation.yang b/models/yang/extensions/openconfig-interfaces-deviation.yang new file mode 100644 index 000000000..e3fd326b7 --- /dev/null +++ b/models/yang/extensions/openconfig-interfaces-deviation.yang @@ -0,0 +1,135 @@ +module openconfig-interfaces-deviation { + + yang-version "1"; + + // namespace + namespace "http://openconfig.net/yang/interfaces/deviation/extension"; + + prefix "oc-intf-dev"; + + // import some basic types + import openconfig-interfaces { prefix oc-intf; } + import openconfig-extensions { prefix oc-ext; } + import openconfig-if-ip {prefix oc-ip; } + import openconfig-vlan { prefix oc-vlan; } + + organization + "SONiC"; + + contact + "SONiC"; + + description + "This module describes a YANG model for openconfig-interfaces deviations."; + + oc-ext:openconfig-version "0.2.7"; + + revision "2024-01-19" { + description + "Add Yang deviations for unsupported subinterfaces."; + reference "0.2.7"; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-intf:state/oc-intf:ifindex { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-intf:state/oc-intf:admin-status { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-intf:state/oc-intf:oper-status { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-intf:state/oc-intf:last-change { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-intf:state/oc-intf:logical { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-intf:state/oc-intf:counters { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-vlan:vlan { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4/oc-ip:addresses/oc-ip:address/oc-ip:state/oc-ip:origin { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4/oc-ip:addresses/oc-ip:address/oc-ip:vrrp { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4/oc-ip:proxy-arp { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4/oc-ip:neighbors { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4/oc-ip:unnumbered { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4/oc-ip:config { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv4/oc-ip:state { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:addresses/oc-ip:address/oc-ip:state/oc-ip:origin { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:addresses/oc-ip:address/oc-ip:state/oc-ip:status { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:addresses/oc-ip:address/oc-ip:vrrp { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:router-advertisement { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:neighbors { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:unnumbered { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:config/oc-ip:enabled { + deviate replace { + default false; + } + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:config/oc-ip:mtu { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:config/oc-ip:dup-addr-detect-transmits { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:config/oc-ip:dhcp-client { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:state { + deviate not-supported; + } + +} diff --git a/models/yang/openconfig-if-ip.yang b/models/yang/openconfig-if-ip.yang index df89662f8..47debfa62 100644 --- a/models/yang/openconfig-if-ip.yang +++ b/models/yang/openconfig-if-ip.yang @@ -390,6 +390,11 @@ module openconfig-if-ip { description "The length of the subnet prefix."; } + + leaf family { + type string; + description "Indicates whether the IP address is IPv4 or IPv6"; + } } grouping ipv4-neighbor-config { @@ -502,6 +507,10 @@ module openconfig-if-ip { description "The length of the subnet prefix."; } + leaf family { + type string; + description "Indicates whether the IP address is IPv4 or IPv6"; + } } grouping ipv6-address-state { diff --git a/models/yang/sonic/import.mk b/models/yang/sonic/import.mk index e52ff765f..7cac2d4e0 100644 --- a/models/yang/sonic/import.mk +++ b/models/yang/sonic/import.mk @@ -5,4 +5,6 @@ # or glob patterns of basenames (like sonic-telemetry*.yang) can be specified. # Other sonic yangs referred by these will also be copied. # -SONICYANG_IMPORTS += sonic-sflow.yang \ No newline at end of file +SONICYANG_IMPORTS += sonic-sflow.yang +SONICYANG_IMPORTS += sonic-interface.yang +SONICYANG_IMPORTS += sonic-port.yang \ No newline at end of file diff --git a/translib/intf_app.go b/translib/intf_app.go deleted file mode 100644 index 4836b1746..000000000 --- a/translib/intf_app.go +++ /dev/null @@ -1,1405 +0,0 @@ -////////////////////////////////////////////////////////////////////////// -// -// 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 translib - -import ( - "errors" - "fmt" - "net" - "reflect" - "regexp" - "strconv" - "strings" - "unsafe" - - "github.com/Azure/sonic-mgmt-common/translib/db" - "github.com/Azure/sonic-mgmt-common/translib/ocbinds" - "github.com/Azure/sonic-mgmt-common/translib/path" - "github.com/Azure/sonic-mgmt-common/translib/tlerr" - log "github.com/golang/glog" - "github.com/openconfig/ygot/ygot" -) - -type reqType int - -const ( - opCreate reqType = iota + 1 - opDelete - opUpdate -) - -type dbEntry struct { - op reqType - entry db.Value -} - -const ( - PORT = "PORT" - PORT_TABLE = "PORT_TABLE" - INTERFACE = "INTERFACE" - COUNTERS_NAME_MAP = "COUNTERS_PORT_NAME_MAP" -) - -const ( - PORT_INDEX = "index" - PORT_MTU = "mtu" - PORT_ADMIN_STATUS = "admin_status" - PORT_SPEED = "speed" - PORT_DESC = "description" - PORT_OPER_STATUS = "oper_status" -) - -// intf_app supports physical ports only; hence consider only -// "EthernetX" fields from COUNTERS_PORT_NAME_MAP -const countersMapFieldPattern = "Ethernet*" - -type Table int - -const ( - IF_TABLE_MAP Table = iota - PORT_STAT_MAP -) - -type IntfApp struct { - path *PathInfo - reqData []byte - ygotRoot *ygot.GoStruct - ygotTarget *interface{} - - respJSON interface{} - allIpKeys []db.Key - - appDB *db.DB - countersDB *db.DB - - ifTableMap map[string]dbEntry - ifIPTableMap map[string]map[string]dbEntry - portOidMap dbEntry - portStatMap map[string]dbEntry - - portTs *db.TableSpec - portTblTs *db.TableSpec - intfIPTs *db.TableSpec - intfIPTblTs *db.TableSpec - intfCountrTblTs *db.TableSpec - portOidCountrTblTs *db.TableSpec -} - -func init() { - log.Info("Init called for INTF module") - err := register("/openconfig-interfaces:interfaces", - &appInfo{appType: reflect.TypeOf(IntfApp{}), - ygotRootType: reflect.TypeOf(ocbinds.OpenconfigInterfaces_Interfaces{}), - isNative: false}) - if err != nil { - log.Fatal("Register INTF app module with App Interface failed with error=", err) - } - - err = addModel(&ModelData{Name: "openconfig-interfaces", - Org: "OpenConfig working group", - Ver: "1.0.2"}) - if err != nil { - log.Fatal("Adding model data to appinterface failed with error=", err) - } -} - -func (app *IntfApp) initialize(data appData) { - log.Info("initialize:if:path =", data.path) - - app.path = NewPathInfo(data.path) - app.reqData = data.payload - app.ygotRoot = data.ygotRoot - app.ygotTarget = data.ygotTarget - - app.portTs = &db.TableSpec{Name: "PORT"} - app.portTblTs = &db.TableSpec{Name: "PORT_TABLE"} - app.intfIPTs = &db.TableSpec{Name: "INTERFACE"} - app.intfIPTblTs = &db.TableSpec{Name: "INTF_TABLE", CompCt: 2} - app.intfCountrTblTs = &db.TableSpec{Name: "COUNTERS"} - app.portOidCountrTblTs = &db.TableSpec{Name: "COUNTERS_PORT_NAME_MAP"} - - app.ifTableMap = make(map[string]dbEntry) - app.ifIPTableMap = make(map[string]map[string]dbEntry) - app.portStatMap = make(map[string]dbEntry) -} - -func (app *IntfApp) getAppRootObject() *ocbinds.OpenconfigInterfaces_Interfaces { - deviceObj := (*app.ygotRoot).(*ocbinds.Device) - return deviceObj.Interfaces -} - -func (app *IntfApp) translateCreate(d *db.DB) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - log.Info("translateCreate:intf:path =", app.path) - - err = errors.New("Not implemented") - return keys, err -} - -func (app *IntfApp) translateUpdate(d *db.DB) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - - log.Info("translateUpdate:intf:path =", app.path) - - keys, err = app.translateCommon(d, opUpdate) - - if err != nil { - log.Info("Something wrong:=", err) - } - - return keys, err -} - -func (app *IntfApp) translateReplace(d *db.DB) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - log.Info("translateReplace:intf:path =", app.path) - err = errors.New("Not implemented") - return keys, err -} - -func (app *IntfApp) translateDelete(d *db.DB) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - pathInfo := app.path - - log.Infof("Received Delete for path %s; vars=%v", pathInfo.Template, pathInfo.Vars) - - intfObj := app.getAppRootObject() - - targetUriPath, err := getYangPathFromUri(app.path.Path) - log.Info("uripath:=", targetUriPath) - log.Info("err:=", err) - - if intfObj.Interface != nil && len(intfObj.Interface) > 0 { - log.Info("len:=", len(intfObj.Interface)) - for ifKey, _ := range intfObj.Interface { - log.Info("Name:=", ifKey) - intf := intfObj.Interface[ifKey] - - if intf.Subinterfaces == nil { - continue - } - subIf := intf.Subinterfaces.Subinterface[0] - if subIf != nil { - if subIf.Ipv4 != nil && subIf.Ipv4.Addresses != nil { - for ip, _ := range subIf.Ipv4.Addresses.Address { - addr := subIf.Ipv4.Addresses.Address[ip] - if addr != nil { - ipAddr := addr.Ip - log.Info("IPv4 address = ", *ipAddr) - if !validIPv4(*ipAddr) { - errStr := "Invalid IPv4 address " + *ipAddr - ipValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ipValidErr - } - err = app.validateIp(d, ifKey, *ipAddr) - if err != nil { - errStr := "Invalid IPv4 address " + *ipAddr - ipValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ipValidErr - } - } - } - } - if subIf.Ipv6 != nil && subIf.Ipv6.Addresses != nil { - for ip, _ := range subIf.Ipv6.Addresses.Address { - addr := subIf.Ipv6.Addresses.Address[ip] - if addr != nil { - ipAddr := addr.Ip - log.Info("IPv6 address = ", *ipAddr) - if !validIPv6(*ipAddr) { - errStr := "Invalid IPv6 address " + *ipAddr - ipValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ipValidErr - } - err = app.validateIp(d, ifKey, *ipAddr) - if err != nil { - errStr := "Invalid IPv6 address:" + *ipAddr - ipValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ipValidErr - } - } - } - } - } else { - err = errors.New("Only subinterface index 0 is supported") - return keys, err - } - } - } else { - err = errors.New("Not implemented") - } - return keys, err -} - -func (app *IntfApp) translateGet(dbs [db.MaxDB]*db.DB) error { - var err error - log.Info("translateGet:intf:path =", app.path) - return err -} - -func (app *IntfApp) translateAction(dbs [db.MaxDB]*db.DB) error { - err := errors.New("Not supported") - return err -} - -func (app *IntfApp) translateSubscribe(req translateSubRequest) (translateSubResponse, error) { - ymap := yangMapTree{ - subtree: map[string]*yangMapTree{ - "interface": { - mapFunc: app.translateSubscribeIntfList, - subtree: map[string]*yangMapTree{ - "state": { - mapFunc: app.translateSubscribeIntfState, - subtree: map[string]*yangMapTree{ - "counters": { - mapFunc: app.translateSubscribeIntfStats, - }, - }, - }, - "subinterfaces/subinterface": { - mapFunc: app.translateSubscribeSubIntf, - subtree: map[string]*yangMapTree{ - "openconfig-if-ip:ipv4/addresses/address": { - mapFunc: app.translateSubscribeIntfIP, - }, - "openconfig-if-ip:ipv6/addresses/address": { - mapFunc: app.translateSubscribeIntfIP, - }, - }, - }, - }}}} - - nb := notificationInfoBuilder{ - pathInfo: NewPathInfo(req.path), - yangMap: ymap, - } - return nb.Build() -} - -func (app *IntfApp) translateSubscribeIntfList(nb *notificationInfoBuilder) error { - name := nb.pathInfo.StringVar("name", "*") - nb.New().PathKey("name", name).Table(db.ConfigDB, PORT).Key(name) - if nb.SetFieldPrefix("config") { - nb.Field("mtu", PORT_MTU) - nb.Field("description", PORT_DESC) - nb.Field("enabled", PORT_ADMIN_STATUS) - } - if nb.SetFieldPrefix("openconfig-if-ethernet:ethernet/config") { - nb.Field("port-speed", PORT_SPEED) - } - if nb.SetFieldPrefix("openconfig-if-ethernet:ethernet/state") { - nb.Field("port-speed", PORT_SPEED) - } - return nil -} - -func (app *IntfApp) translateSubscribeIntfState(nb *notificationInfoBuilder) error { - name := nb.pathInfo.StringVar("name", "*") - nb.New().Table(db.ApplDB, PORT_TABLE).Key(name) - if nb.SetFieldPrefix("") { - nb.Field("ifindex", PORT_INDEX) - nb.Field("mtu", PORT_MTU) - nb.Field("description", PORT_DESC) - nb.Field("enabled", PORT_ADMIN_STATUS) - nb.Field("admin-status", PORT_ADMIN_STATUS) - nb.Field("oper-status", PORT_OPER_STATUS) - } - return nil -} - -func (app *IntfApp) translateSubscribeIntfStats(nb *notificationInfoBuilder) error { - name := nb.pathInfo.StringVar("name", "*") - fieldPattern := name - if name == "*" { - fieldPattern = countersMapFieldPattern - } - nb.New().Table(db.CountersDB, COUNTERS_NAME_MAP).FieldScan(fieldPattern) - return nil -} - -func (app *IntfApp) translateSubscribeSubIntf(nb *notificationInfoBuilder) error { - index := nb.pathInfo.StringVar("index", "*") - if index != "*" && index != "0" { - return tlerr.InvalidArgs("invalid subinterface index: %s", index) - } - nb.PathKey("index", "0") - return nil -} - -func (app *IntfApp) translateSubscribeIntfIP(nb *notificationInfoBuilder) error { - name := nb.pathInfo.StringVar("name", "*") - ipV := 4 // 4 or 6 - if p := path.GetElemAt(nb.currentPath, 4); strings.HasSuffix(p, "ipv6") { - ipV = 6 - } - - addr := nb.pathInfo.StringVar("ip", "*") - var addrDbPattern string - if addr != "*" { - if (ipV == 4 && !validIPv4(addr)) || (ipV == 6 && !validIPv6(addr)) { - return tlerr.InvalidArgs("not a valid ipv%d address: %s", ipV, addr) - } - addrDbPattern = addr + "/*" - } else if ipV == 4 { - addrDbPattern = "*.*.*.*/*" - } else { - addrDbPattern = "*:*/*" // ipv6 address will have at least 1 colon - } - - nb.New().PathKey("ip", addr).Table(db.ConfigDB, INTERFACE).Key(name, addrDbPattern) - if nb.SetFieldPrefix("config") { - nb.Field("prefix-length", "") - } - if nb.SetFieldPrefix("state") { - nb.Field("prefix-length", "") - } - return nil -} - -func (app *IntfApp) processSubscribe(req processSubRequest) (processSubResponse, error) { - resp := processSubResponse{ - path: req.path, - } - switch req.table.Name { - case PORT, PORT_TABLE, COUNTERS_NAME_MAP: - path.SetKeyAt(resp.path, 1, "name", req.key.Get(0)) - case INTERFACE: - if req.key.Len() != 2 { - return resp, tlerr.New("unsupported interface key: %v", req.key) - } - path.SetKeyAt(resp.path, 1, "name", req.key.Get(0)) - path.SetKeyAt(resp.path, 3, "index", "0") - path.SetKeyAt(resp.path, 6, "ip", strings.Split(req.key.Get(1), "/")[0]) // trim subnet mask - default: - return resp, tlerr.New("unsupported table: %s", req.table.Name) - } - return resp, nil -} - -func (app *IntfApp) processCreate(d *db.DB) (SetResponse, error) { - var err error - var resp SetResponse - - log.Info("processCreate:intf:path =", app.path) - log.Info("ProcessCreate: Target Type is " + reflect.TypeOf(*app.ygotTarget).Elem().Name()) - - err = errors.New("Not implemented") - return resp, err -} - -func (app *IntfApp) processUpdate(d *db.DB) (SetResponse, error) { - - log.Infof("Calling processCommon()") - - resp, err := app.processCommon(d) - return resp, err -} - -func (app *IntfApp) processReplace(d *db.DB) (SetResponse, error) { - var err error - var resp SetResponse - log.Info("processReplace:intf:path =", app.path) - err = errors.New("Not implemented") - return resp, err -} - -func (app *IntfApp) processDelete(d *db.DB) (SetResponse, error) { - var err error - var resp SetResponse - log.Info("processDelete:intf:path =", app.path) - - if len(app.ifIPTableMap) == 0 { - return resp, err - } - for ifKey, entrylist := range app.ifIPTableMap { - for ip, _ := range entrylist { - err = d.DeleteEntry(app.intfIPTs, db.Key{Comp: []string{ifKey, ip}}) - log.Infof("Deleted IP : %s for Interface : %s", ip, ifKey) - } - } - return resp, err -} - -/* Note : Registration already happened, followed by filling the internal DS and filling the JSON */ -func (app *IntfApp) processGet(dbs [db.MaxDB]*db.DB, fmtType TranslibFmtType) (GetResponse, error) { - - var err error - var payload []byte - pathInfo := app.path - - log.Infof("Received GET for path %s; template: %s vars=%v", pathInfo.Path, pathInfo.Template, pathInfo.Vars) - app.appDB = dbs[db.ApplDB] - app.countersDB = dbs[db.CountersDB] - - intfObj := app.getAppRootObject() - - targetUriPath, err := getYangPathFromUri(app.path.Path) - log.Info("URI Path = ", targetUriPath) - - if isSubtreeRequest(targetUriPath, "/openconfig-interfaces:interfaces/interface") { - /* Request for a specific interface */ - if intfObj.Interface != nil && len(intfObj.Interface) > 0 { - /* Interface name is the key */ - for ifKey, _ := range intfObj.Interface { - log.Info("Interface Name = ", ifKey) - ifInfo := intfObj.Interface[ifKey] - /* Filling Interface Info to internal DS */ - err = app.convertDBIntfInfoToInternal(app.appDB, ifKey, db.Key{Comp: []string{ifKey}}) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - - /*Check if the request is for a specific attribute in Interfaces state container*/ - oc_val := &ocbinds.OpenconfigInterfaces_Interfaces_Interface_State{} - ok, e := app.getSpecificAttr(targetUriPath, ifKey, oc_val) - if ok { - if e != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, e - } - - ifInfo.State = oc_val - continue - } - - /* Filling the counter Info to internal DS */ - err = app.getPortOidMapForCounters(app.countersDB) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - err = app.convertDBIntfCounterInfoToInternal(app.countersDB, ifKey) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - - /*Check if the request is for a specific attribute in Interfaces state COUNTERS container*/ - counter_val := &ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_Counters{} - ok, e = app.getSpecificCounterAttr(targetUriPath, ifKey, counter_val) - if ok { - if e != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, e - } - - ifInfo.State = &ocbinds.OpenconfigInterfaces_Interfaces_Interface_State{Counters: counter_val} - continue - } - - /* Filling Interface IP info to internal DS */ - err = app.convertDBIntfIPInfoToInternal(app.appDB, ifKey) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - - /* Filling the tree with the info we have in Internal DS */ - ygot.BuildEmptyTree(ifInfo) - if *app.ygotTarget == ifInfo.State { - ygot.BuildEmptyTree(ifInfo.State) - } - app.convertInternalToOCIntfInfo(&ifKey, ifInfo) - } - } - - return generateGetResponse(pathInfo.Path, app.ygotRoot, fmtType) - } - - /* Get all Interfaces */ - if isSubtreeRequest(targetUriPath, "/openconfig-interfaces:interfaces") { - log.Info("Get all Interfaces request!") - /* Filling Interface Info to internal DS */ - err = app.convertDBIntfInfoToInternal(app.appDB, "", db.Key{}) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - /* Filling Interface IP info to internal DS */ - err = app.convertDBIntfIPInfoToInternal(app.appDB, "") - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - /* Filling the counter Info to internal DS */ - err = app.getPortOidMapForCounters(app.countersDB) - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - err = app.convertDBIntfCounterInfoToInternal(app.countersDB, "") - if err != nil { - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - ygot.BuildEmptyTree(intfObj) - for ifKey, _ := range app.ifTableMap { - log.Info("If Key = ", ifKey) - ifInfo, err := intfObj.NewInterface(ifKey) - if err != nil { - log.Errorf("Creation of interface subtree for %s failed!", ifKey) - return GetResponse{Payload: payload, ErrSrc: AppErr}, err - } - ygot.BuildEmptyTree(ifInfo) - app.convertInternalToOCIntfInfo(&ifKey, ifInfo) - } - } - - return generateGetResponse(pathInfo.Path, app.ygotRoot, fmtType) -} - -func (app *IntfApp) processAction(dbs [db.MaxDB]*db.DB) (ActionResponse, error) { - var resp ActionResponse - err := errors.New("Not implemented") - - return resp, err -} - -/* Checking IP adderss is v4 */ -func validIPv4(ipAddress string) bool { - ipAddress = strings.Trim(ipAddress, " ") - - re, _ := regexp.Compile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`) - if re.MatchString(ipAddress) { - return true - } - return false -} - -/* Checking IP address is v6 */ -func validIPv6(ip6Address string) bool { - ip6Address = strings.Trim(ip6Address, " ") - re, _ := regexp.Compile(`(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`) - if re.MatchString(ip6Address) { - return true - } - return false -} - -func (app *IntfApp) doGetAllIpKeys(d *db.DB, dbSpec *db.TableSpec) ([]db.Key, error) { - - var keys []db.Key - - intfTable, err := d.GetTable(dbSpec) - if err != nil { - return keys, err - } - - keys, err = intfTable.GetKeys() - log.Infof("Found %d INTF table keys", len(keys)) - return keys, err -} - -func (app *IntfApp) getSpecificAttr(targetUriPath string, ifKey string, oc_val *ocbinds.OpenconfigInterfaces_Interfaces_Interface_State) (bool, error) { - switch targetUriPath { - case "/openconfig-interfaces:interfaces/interface/state/oper-status": - val, e := app.getIntfAttr(ifKey, PORT_OPER_STATUS, IF_TABLE_MAP) - if len(val) > 0 { - switch val { - case "up": - oc_val.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UP - case "down": - oc_val.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_DOWN - default: - oc_val.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UNSET - } - return true, nil - } else { - return true, e - } - case "/openconfig-interfaces:interfaces/interface/state/admin-status": - val, e := app.getIntfAttr(ifKey, PORT_ADMIN_STATUS, IF_TABLE_MAP) - if len(val) > 0 { - switch val { - case "up": - oc_val.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UP - case "down": - oc_val.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_DOWN - default: - oc_val.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UNSET - } - return true, nil - } else { - return true, e - } - case "/openconfig-interfaces:interfaces/interface/state/mtu": - val, e := app.getIntfAttr(ifKey, PORT_MTU, IF_TABLE_MAP) - if len(val) > 0 { - v, e := strconv.ParseUint(val, 10, 16) - if e == nil { - oc_val.Mtu = (*uint16)(unsafe.Pointer(&v)) - return true, nil - } - } - return true, e - case "/openconfig-interfaces:interfaces/interface/state/ifindex": - val, e := app.getIntfAttr(ifKey, PORT_INDEX, IF_TABLE_MAP) - if len(val) > 0 { - v, e := strconv.ParseUint(val, 10, 32) - if e == nil { - oc_val.Ifindex = (*uint32)(unsafe.Pointer(&v)) - return true, nil - } - } - return true, e - case "/openconfig-interfaces:interfaces/interface/state/description": - val, e := app.getIntfAttr(ifKey, PORT_DESC, IF_TABLE_MAP) - if e == nil { - oc_val.Description = &val - return true, nil - } - return true, e - - default: - log.Infof(targetUriPath + " - Not an interface state attribute") - } - return false, nil -} - -func (app *IntfApp) getSpecificCounterAttr(targetUriPath string, ifKey string, counter_val *ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_Counters) (bool, error) { - - var e error - - switch targetUriPath { - case "/openconfig-interfaces:interfaces/interface/state/counters/in-octets": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_OCTETS", &counter_val.InOctets) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-unicast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_UCAST_PKTS", &counter_val.InUnicastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-broadcast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_BROADCAST_PKTS", &counter_val.InBroadcastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-multicast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_MULTICAST_PKTS", &counter_val.InMulticastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-errors": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_ERRORS", &counter_val.InErrors) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-discards": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_DISCARDS", &counter_val.InDiscards) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/in-pkts": - var inNonUCastPkt, inUCastPkt *uint64 - var in_pkts uint64 - - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS", &inNonUCastPkt) - if e == nil { - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_IN_UCAST_PKTS", &inUCastPkt) - if e != nil { - return true, e - } - in_pkts = *inUCastPkt + *inNonUCastPkt - counter_val.InPkts = &in_pkts - return true, e - } else { - return true, e - } - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-octets": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_OCTETS", &counter_val.OutOctets) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-unicast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_UCAST_PKTS", &counter_val.OutUnicastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-broadcast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_BROADCAST_PKTS", &counter_val.OutBroadcastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-multicast-pkts": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_MULTICAST_PKTS", &counter_val.OutMulticastPkts) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-errors": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_ERRORS", &counter_val.OutErrors) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-discards": - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_DISCARDS", &counter_val.OutDiscards) - return true, e - - case "/openconfig-interfaces:interfaces/interface/state/counters/out-pkts": - var outNonUCastPkt, outUCastPkt *uint64 - var out_pkts uint64 - - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS", &outNonUCastPkt) - if e == nil { - e = app.getCounters(ifKey, "SAI_PORT_STAT_IF_OUT_UCAST_PKTS", &outUCastPkt) - if e != nil { - return true, e - } - out_pkts = *outUCastPkt + *outNonUCastPkt - counter_val.OutPkts = &out_pkts - return true, e - } else { - return true, e - } - - default: - log.Infof(targetUriPath + " - Not an interface state counter attribute") - } - return false, nil -} - -func (app *IntfApp) getCounters(ifKey string, attr string, counter_val **uint64) error { - val, e := app.getIntfAttr(ifKey, attr, PORT_STAT_MAP) - if len(val) > 0 { - v, e := strconv.ParseUint(val, 10, 64) - if e == nil { - *counter_val = &v - return nil - } - } - return e -} - -func (app *IntfApp) getIntfAttr(ifName string, attr string, table Table) (string, error) { - - var ok bool = false - var entry dbEntry - - if table == IF_TABLE_MAP { - entry, ok = app.ifTableMap[ifName] - } else if table == PORT_STAT_MAP { - entry, ok = app.portStatMap[ifName] - } else { - return "", errors.New("Unsupported table") - } - - if ok { - ifData := entry.entry - - if val, ok := ifData.Field[attr]; ok { - return val, nil - } - } - return "", errors.New("Attr " + attr + "doesn't exist in IF table Map!") -} - -func (app *IntfApp) shouldLoad(p string) bool { - return strings.HasPrefix(p, app.path.Template) || strings.HasPrefix(app.path.Template, p) -} - -/*********** Translation Helper fn to convert DB Interface info to Internal DS ***********/ -func (app *IntfApp) getPortOidMapForCounters(dbCl *db.DB) error { - if !app.shouldLoad("/openconfig-interfaces:interfaces/interface{}/state/counters") { - return nil - } - - var err error - ifCountInfo, err := dbCl.GetMapAll(app.portOidCountrTblTs) - if err != nil { - log.Error("Port-OID (Counters) get for all the interfaces failed!") - return err - } - if ifCountInfo.IsPopulated() { - app.portOidMap.entry = ifCountInfo - } else { - return errors.New("Get for OID info from all the interfaces from Counters DB failed!") - } - return err -} - -func (app *IntfApp) convertDBIntfCounterInfoToInternal(dbCl *db.DB, ifKey string) error { - if !app.shouldLoad("/openconfig-interfaces:interfaces/interface{}/state/counters") { - return nil - } - - var err error - if len(ifKey) > 0 { - oid := app.portOidMap.entry.Field[ifKey] - log.Infof("OID : %s received for Interface : %s", oid, ifKey) - - /* Get the statistics for the port */ - var ifStatKey db.Key - ifStatKey.Comp = []string{oid} - - ifStatInfo, err := dbCl.GetEntry(app.intfCountrTblTs, ifStatKey) - if err != nil { - log.Infof("Fetching port-stat for port : %s failed!", ifKey) - return err - } - app.portStatMap[ifKey] = dbEntry{entry: ifStatInfo} - } else { - for ifKey, _ := range app.ifTableMap { - app.convertDBIntfCounterInfoToInternal(dbCl, ifKey) - } - } - return err -} - -func (app *IntfApp) validateInterface(dbCl *db.DB, ifName string, ifKey db.Key) error { - var err error - if len(ifName) == 0 { - return errors.New("Empty Interface name") - } - app.portTblTs = &db.TableSpec{Name: "PORT_TABLE"} - _, err = dbCl.GetEntry(app.portTblTs, ifKey) - if err != nil { - log.Errorf("Error found on fetching Interface info from App DB for If Name : %s", ifName) - errStr := "Invalid Interface:" + ifName - err = tlerr.InvalidArgsError{Format: errStr} - return err - } - return err -} - -func (app *IntfApp) convertDBIntfInfoToInternal(dbCl *db.DB, ifName string, ifKey db.Key) error { - - var err error - /* Fetching DB data for a specific Interface */ - if len(ifName) > 0 { - log.Info("Updating Interface info from APP-DB to Internal DS for Interface name : ", ifName) - ifInfo, err := dbCl.GetEntry(app.portTblTs, ifKey) - if err != nil { - log.Errorf("Error found on fetching Interface info from App DB for If Name : %s", ifName) - errStr := "Invalid Interface:" + ifName - err = tlerr.InvalidArgsError{Format: errStr} - return err - } - if ifInfo.IsPopulated() { - log.Info("Interface Info populated for ifName : ", ifName) - app.ifTableMap[ifName] = dbEntry{entry: ifInfo} - } else { - return errors.New("Populating Interface info for " + ifName + "failed") - } - } else { - log.Info("App-DB get for all the interfaces") - tbl, err := dbCl.GetTable(app.portTblTs) - if err != nil { - log.Error("App-DB get for list of interfaces failed!") - return err - } - keys, _ := tbl.GetKeys() - for _, key := range keys { - app.convertDBIntfInfoToInternal(dbCl, key.Get(0), db.Key{Comp: []string{key.Get(0)}}) - } - } - return err -} - -/*********** Translation Helper fn to convert DB Interface IP info to Internal DS ***********/ -func (app *IntfApp) convertDBIntfIPInfoToInternal(dbCl *db.DB, ifName string) error { - if !app.shouldLoad("/openconfig-interfaces:interfaces/interface{}/subinterfaces") { - return nil - } - - var err error - log.Info("Updating Interface IP Info from APP-DB to Internal DS for Interface Name : ", ifName) - app.allIpKeys, _ = app.doGetAllIpKeys(dbCl, app.intfIPTblTs) - - for _, key := range app.allIpKeys { - if len(key.Comp) <= 1 { - continue - } - ipInfo, err := dbCl.GetEntry(app.intfIPTblTs, key) - if err != nil { - log.Errorf("Error found on fetching Interface IP info from App DB for Interface Name : %s", ifName) - return err - } - if len(app.ifIPTableMap[key.Get(0)]) == 0 { - app.ifIPTableMap[key.Get(0)] = make(map[string]dbEntry) - app.ifIPTableMap[key.Get(0)][key.Get(1)] = dbEntry{entry: ipInfo} - } else { - app.ifIPTableMap[key.Get(0)][key.Get(1)] = dbEntry{entry: ipInfo} - } - } - return err -} - -func (app *IntfApp) convertInternalToOCIntfInfo(ifName *string, ifInfo *ocbinds.OpenconfigInterfaces_Interfaces_Interface) { - app.convertInternalToOCIntfAttrInfo(ifName, ifInfo) - app.convertInternalToOCIntfIPAttrInfo(ifName, ifInfo) - app.convertInternalToOCPortStatInfo(ifName, ifInfo) -} - -func (app *IntfApp) convertInternalToOCIntfAttrInfo(ifName *string, ifInfo *ocbinds.OpenconfigInterfaces_Interfaces_Interface) { - - /* Handling the Interface attributes */ - if entry, ok := app.ifTableMap[*ifName]; ok { - ifData := entry.entry - - name := *ifName - ifInfo.Config.Name = &name - ifInfo.State.Name = &name - - for ifAttr := range ifData.Field { - switch ifAttr { - case PORT_ADMIN_STATUS: - adminStatus := ifData.Get(ifAttr) - ifInfo.State.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_DOWN - if adminStatus == "up" { - ifInfo.State.AdminStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UP - } - case PORT_OPER_STATUS: - operStatus := ifData.Get(ifAttr) - ifInfo.State.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_DOWN - if operStatus == "up" { - ifInfo.State.OperStatus = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UP - } - case PORT_DESC: - descVal := ifData.Get(ifAttr) - descr := new(string) - *descr = descVal - ifInfo.Config.Description = descr - ifInfo.State.Description = descr - case PORT_MTU: - mtuStr := ifData.Get(ifAttr) - mtuVal, err := strconv.Atoi(mtuStr) - mtu := new(uint16) - *mtu = uint16(mtuVal) - if err == nil { - ifInfo.Config.Mtu = mtu - ifInfo.State.Mtu = mtu - } - case PORT_SPEED: - speed := ifData.Get(ifAttr) - var speedEnum ocbinds.E_OpenconfigIfEthernet_ETHERNET_SPEED - - switch speed { - case "2500": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_2500MB - case "1000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_1GB - case "5000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_5GB - case "10000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_10GB - case "25000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_25GB - case "40000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_40GB - case "50000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_50GB - case "100000": - speedEnum = ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_100GB - default: - log.Infof("Not supported speed: %s!", speed) - } - ifInfo.Ethernet.Config.PortSpeed = speedEnum - ifInfo.Ethernet.State.PortSpeed = speedEnum - case PORT_INDEX: - ifIdxStr := ifData.Get(ifAttr) - ifIdxNum, err := strconv.Atoi(ifIdxStr) - if err == nil { - ifIdx := new(uint32) - *ifIdx = uint32(ifIdxNum) - ifInfo.State.Ifindex = ifIdx - } - default: - log.Info("Not a valid attribute!") - } - } - } - -} - -func (app *IntfApp) convertInternalToOCIntfIPAttrInfo(ifName *string, ifInfo *ocbinds.OpenconfigInterfaces_Interfaces_Interface) { - - /* Handling the Interface IP attributes */ - subIntf, err := ifInfo.Subinterfaces.NewSubinterface(0) - if err != nil { - log.Error("Creation of subinterface subtree failed!") - return - } - ygot.BuildEmptyTree(subIntf) - if ipMap, ok := app.ifIPTableMap[*ifName]; ok { - for ipKey, _ := range ipMap { - log.Info("IP address = ", ipKey) - ipB, ipNetB, _ := net.ParseCIDR(ipKey) - - v4Flag := false - v6Flag := false - - var v4Address *ocbinds.OpenconfigInterfaces_Interfaces_Interface_Subinterfaces_Subinterface_Ipv4_Addresses_Address - var v6Address *ocbinds.OpenconfigInterfaces_Interfaces_Interface_Subinterfaces_Subinterface_Ipv6_Addresses_Address - - if validIPv4(ipB.String()) { - v4Address, err = subIntf.Ipv4.Addresses.NewAddress(ipB.String()) - v4Flag = true - } else if validIPv6(ipB.String()) { - v6Address, err = subIntf.Ipv6.Addresses.NewAddress(ipB.String()) - v6Flag = true - } else { - log.Error("Invalid IP address " + ipB.String()) - continue - } - - if err != nil { - log.Error("Creation of address subtree failed!") - return - } - if v4Flag { - ygot.BuildEmptyTree(v4Address) - - ipStr := new(string) - *ipStr = ipB.String() - v4Address.Ip = ipStr - v4Address.Config.Ip = ipStr - v4Address.State.Ip = ipStr - - ipNetBNum, _ := ipNetB.Mask.Size() - prfxLen := new(uint8) - *prfxLen = uint8(ipNetBNum) - v4Address.Config.PrefixLength = prfxLen - v4Address.State.PrefixLength = prfxLen - } - if v6Flag { - ygot.BuildEmptyTree(v6Address) - - ipStr := new(string) - *ipStr = ipB.String() - v6Address.Ip = ipStr - v6Address.Config.Ip = ipStr - v6Address.State.Ip = ipStr - - ipNetBNum, _ := ipNetB.Mask.Size() - prfxLen := new(uint8) - *prfxLen = uint8(ipNetBNum) - v6Address.Config.PrefixLength = prfxLen - v6Address.State.PrefixLength = prfxLen - } - } - } -} - -func (app *IntfApp) convertInternalToOCPortStatInfo(ifName *string, ifInfo *ocbinds.OpenconfigInterfaces_Interfaces_Interface) { - if len(app.portStatMap) == 0 { - log.Errorf("Port stat info not present for interface : %s", *ifName) - return - } - if portStatInfo, ok := app.portStatMap[*ifName]; ok { - - inOctet := new(uint64) - inOctetVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_OCTETS"]) - *inOctet = uint64(inOctetVal) - ifInfo.State.Counters.InOctets = inOctet - - inUCastPkt := new(uint64) - inUCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_UCAST_PKTS"]) - *inUCastPkt = uint64(inUCastPktVal) - ifInfo.State.Counters.InUnicastPkts = inUCastPkt - - inNonUCastPkt := new(uint64) - inNonUCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS"]) - *inNonUCastPkt = uint64(inNonUCastPktVal) - - inPkt := new(uint64) - *inPkt = *inUCastPkt + *inNonUCastPkt - ifInfo.State.Counters.InPkts = inPkt - - inBCastPkt := new(uint64) - inBCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_BROADCAST_PKTS"]) - *inBCastPkt = uint64(inBCastPktVal) - ifInfo.State.Counters.InBroadcastPkts = inBCastPkt - - inMCastPkt := new(uint64) - inMCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_MULTICAST_PKTS"]) - *inMCastPkt = uint64(inMCastPktVal) - ifInfo.State.Counters.InMulticastPkts = inMCastPkt - - inErrPkt := new(uint64) - inErrPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_ERRORS"]) - *inErrPkt = uint64(inErrPktVal) - ifInfo.State.Counters.InErrors = inErrPkt - - inDiscPkt := new(uint64) - inDiscPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_IN_DISCARDS"]) - *inDiscPkt = uint64(inDiscPktVal) - ifInfo.State.Counters.InDiscards = inDiscPkt - - outOctet := new(uint64) - outOctetVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_OCTETS"]) - *outOctet = uint64(outOctetVal) - ifInfo.State.Counters.OutOctets = outOctet - - outUCastPkt := new(uint64) - outUCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_UCAST_PKTS"]) - *outUCastPkt = uint64(outUCastPktVal) - ifInfo.State.Counters.OutUnicastPkts = outUCastPkt - - outNonUCastPkt := new(uint64) - outNonUCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS"]) - *outNonUCastPkt = uint64(outNonUCastPktVal) - - outPkt := new(uint64) - *outPkt = *outUCastPkt + *outNonUCastPkt - ifInfo.State.Counters.OutPkts = outPkt - - outBCastPkt := new(uint64) - outBCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_BROADCAST_PKTS"]) - *outBCastPkt = uint64(outBCastPktVal) - ifInfo.State.Counters.OutBroadcastPkts = outBCastPkt - - outMCastPkt := new(uint64) - outMCastPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_MULTICAST_PKTS"]) - *outMCastPkt = uint64(outMCastPktVal) - ifInfo.State.Counters.OutMulticastPkts = outMCastPkt - - outErrPkt := new(uint64) - outErrPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_ERRORS"]) - *outErrPkt = uint64(outErrPktVal) - ifInfo.State.Counters.OutErrors = outErrPkt - - outDiscPkt := new(uint64) - outDiscPktVal, _ := strconv.Atoi(portStatInfo.entry.Field["SAI_PORT_STAT_IF_OUT_DISCARDS"]) - *outDiscPkt = uint64(outDiscPktVal) - ifInfo.State.Counters.OutDiscards = outDiscPkt - } -} - -func (app *IntfApp) translateCommon(d *db.DB, inpOp reqType) ([]db.WatchKeys, error) { - var err error - var keys []db.WatchKeys - pathInfo := app.path - - log.Infof("Received UPDATE for path %s; vars=%v", pathInfo.Template, pathInfo.Vars) - - app.allIpKeys, _ = app.doGetAllIpKeys(d, app.intfIPTs) - - intfObj := app.getAppRootObject() - - targetUriPath, err := getYangPathFromUri(app.path.Path) - log.Info("uripath:=", targetUriPath) - log.Info("err:=", err) - - if intfObj.Interface != nil && len(intfObj.Interface) > 0 { - log.Info("len:=", len(intfObj.Interface)) - for ifKey, _ := range intfObj.Interface { - log.Info("Name:=", ifKey) - intf := intfObj.Interface[ifKey] - curr, err := d.GetEntry(app.portTs, db.Key{Comp: []string{ifKey}}) - if err != nil { - errStr := "Invalid Interface:" + ifKey - ifValidErr := tlerr.InvalidArgsError{Format: errStr} - return keys, ifValidErr - } - if !curr.IsPopulated() { - log.Error("Interface ", ifKey, " doesn't exist in DB") - return keys, errors.New("Interface: " + ifKey + " doesn't exist in DB") - } - if intf.Config != nil { - if intf.Config.Description != nil { - log.Info("Description = ", *intf.Config.Description) - curr.Field["description"] = *intf.Config.Description - } else if intf.Config.Mtu != nil { - log.Info("mtu:= ", *intf.Config.Mtu) - curr.Field["mtu"] = strconv.Itoa(int(*intf.Config.Mtu)) - } else if intf.Config.Enabled != nil { - log.Info("enabled = ", *intf.Config.Enabled) - if *intf.Config.Enabled == true { - curr.Field["admin_status"] = "up" - } else { - curr.Field["admin_status"] = "down" - } - } - log.Info("Writing to db for ", ifKey) - var entry dbEntry - entry.op = opUpdate - entry.entry = curr - - app.ifTableMap[ifKey] = entry - } - if intf.Subinterfaces == nil { - continue - } - subIf := intf.Subinterfaces.Subinterface[0] - if subIf != nil { - if subIf.Ipv4 != nil && subIf.Ipv4.Addresses != nil { - for ip, _ := range subIf.Ipv4.Addresses.Address { - addr := subIf.Ipv4.Addresses.Address[ip] - if addr.Config != nil { - log.Info("Ip:=", *addr.Config.Ip) - log.Info("prefix:=", *addr.Config.PrefixLength) - if !validIPv4(*addr.Config.Ip) { - errStr := "Invalid IPv4 address " + *addr.Config.Ip - err = tlerr.InvalidArgsError{Format: errStr} - return keys, err - } - err = app.translateIpv4(d, ifKey, *addr.Config.Ip, int(*addr.Config.PrefixLength)) - if err != nil { - return keys, err - } - } - } - } - if subIf.Ipv6 != nil && subIf.Ipv6.Addresses != nil { - for ip, _ := range subIf.Ipv6.Addresses.Address { - addr := subIf.Ipv6.Addresses.Address[ip] - if addr.Config != nil { - log.Info("Ip:=", *addr.Config.Ip) - log.Info("prefix:=", *addr.Config.PrefixLength) - if !validIPv6(*addr.Config.Ip) { - errStr := "Invalid IPv6 address " + *addr.Config.Ip - err = tlerr.InvalidArgsError{Format: errStr} - return keys, err - } - err = app.translateIpv4(d, ifKey, *addr.Config.Ip, int(*addr.Config.PrefixLength)) - if err != nil { - return keys, err - } - } - } - } - } else { - err = errors.New("Only subinterface index 0 is supported") - return keys, err - } - } - } else { - err = errors.New("Not implemented") - } - - return keys, err -} - -/* Validates whether the IP exists in the DB */ -func (app *IntfApp) validateIp(dbCl *db.DB, ifName string, ip string) error { - app.allIpKeys, _ = app.doGetAllIpKeys(dbCl, app.intfIPTs) - - for _, key := range app.allIpKeys { - if len(key.Comp) < 2 { - continue - } - if key.Get(0) != ifName { - continue - } - ipAddr, _, _ := net.ParseCIDR(key.Get(1)) - ipStr := ipAddr.String() - if ipStr == ip { - log.Infof("IP address %s exists, updating the DS for deletion!", ipStr) - ipInfo, err := dbCl.GetEntry(app.intfIPTs, key) - if err != nil { - log.Error("Error found on fetching Interface IP info from App DB for Interface Name : ", ifName) - return err - } - if len(app.ifIPTableMap[key.Get(0)]) == 0 { - app.ifIPTableMap[key.Get(0)] = make(map[string]dbEntry) - app.ifIPTableMap[key.Get(0)][key.Get(1)] = dbEntry{entry: ipInfo} - } else { - app.ifIPTableMap[key.Get(0)][key.Get(1)] = dbEntry{entry: ipInfo} - } - return nil - } - } - return errors.New(fmt.Sprintf("IP address : %s doesn't exist!", ip)) -} - -func (app *IntfApp) translateIpv4(d *db.DB, intf string, ip string, prefix int) error { - var err error - var ifsKey db.Key - - ifsKey.Comp = []string{intf} - - ipPref := ip + "/" + strconv.Itoa(prefix) - ifsKey.Comp = []string{intf, ipPref} - - log.Info("ifsKey:=", ifsKey) - - log.Info("Checking for IP overlap ....") - ipA, ipNetA, _ := net.ParseCIDR(ipPref) - - for _, key := range app.allIpKeys { - if len(key.Comp) < 2 { - continue - } - ipB, ipNetB, _ := net.ParseCIDR(key.Get(1)) - - if ipNetA.Contains(ipB) || ipNetB.Contains(ipA) { - log.Info("IP ", ipPref, "overlaps with ", key.Get(1), " of ", key.Get(0)) - - if intf != key.Get(0) { - //IP overlap across different interface, reject - log.Error("IP ", ipPref, " overlaps with ", key.Get(1), " of ", key.Get(0)) - - errStr := "IP " + ipPref + " overlaps with IP " + key.Get(1) + " of Interface " + key.Get(0) - err = tlerr.InvalidArgsError{Format: errStr} - return err - } else { - //IP overlap on same interface, replace - var entry dbEntry - entry.op = opDelete - - log.Info("Entry ", key.Get(1), " on ", intf, " needs to be deleted") - if app.ifIPTableMap[intf] == nil { - app.ifIPTableMap[intf] = make(map[string]dbEntry) - } - app.ifIPTableMap[intf][key.Get(1)] = entry - } - } - } - - //At this point, we need to add the entry to db - { - var entry dbEntry - entry.op = opCreate - - m := make(map[string]string) - m["NULL"] = "NULL" - value := db.Value{Field: m} - entry.entry = value - if app.ifIPTableMap[intf] == nil { - app.ifIPTableMap[intf] = make(map[string]dbEntry) - } - app.ifIPTableMap[intf][ipPref] = entry - } - return err -} - -func (app *IntfApp) processCommon(d *db.DB) (SetResponse, error) { - var err error - var resp SetResponse - - log.Info("processCommon:intf:path =", app.path) - log.Info("ProcessCommon: Target Type is " + reflect.TypeOf(*app.ygotTarget).Elem().Name()) - - for key, entry := range app.ifTableMap { - if entry.op == opUpdate { - log.Info("Updating entry for ", key) - err = d.SetEntry(app.portTs, db.Key{Comp: []string{key}}, entry.entry) - } - } - - for key, entry1 := range app.ifIPTableMap { - ifEntry, err := d.GetEntry(app.intfIPTs, db.Key{Comp: []string{key}}) - if err != nil || !ifEntry.IsPopulated() { - log.Infof("Interface Entry not present for Key:%s for IP config!", key) - m := make(map[string]string) - m["NULL"] = "NULL" - err = d.CreateEntry(app.intfIPTs, db.Key{Comp: []string{key}}, db.Value{Field: m}) - if err != nil { - return resp, err - } - log.Infof("Created Interface entry with Interface name : %s alone!", key) - } - for ip, entry := range entry1 { - if entry.op == opCreate { - log.Info("Creating entry for ", key, ":", ip) - err = d.CreateEntry(app.intfIPTs, db.Key{Comp: []string{key, ip}}, entry.entry) - } else if entry.op == opDelete { - log.Info("Deleting entry for ", key, ":", ip) - err = d.DeleteEntry(app.intfIPTs, db.Key{Comp: []string{key, ip}}) - } - } - } - return resp, err -} diff --git a/translib/intf_app_test.go b/translib/intf_app_test.go deleted file mode 100644 index a3e72a86d..000000000 --- a/translib/intf_app_test.go +++ /dev/null @@ -1,240 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// // -// Copyright 2023 Broadcom. The term Broadcom refers to Broadcom Inc. and/or // -// its subsidiaries. // -// // -// 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 translib - -import ( - "fmt" - "testing" - - "github.com/Azure/sonic-mgmt-common/translib/db" -) - -func TestIntfApp_translateSubscribe(t *testing.T) { - - for _, ifName := range []string{"", "*", "Ethernet123"} { - t.Run(fmt.Sprintf("top[name=%s]", ifName), func(t *testing.T) { - reqPath := "/openconfig-interfaces:interfaces" - if len(ifName) != 0 { - reqPath += fmt.Sprintf("/interface[name=%s]", ifName) - } else { - ifName = "*" - } - - ifPath := fmt.Sprintf("/openconfig-interfaces:interfaces/interface[name=%s]", ifName) - tv := testTranslateSubscribe(t, reqPath) - tv.VerifyCount(1, 4) - tv.VerifyTarget( - ifPath, portConfigNInfo(ifName, portConfigAllFields)) - tv.VerifyChild( - ifPath+"/state", portStateNInfo(ifName, portStateAllFields)) - tv.VerifyChild( - ifPath+"/state/counters", portCountersNInfo(ifName)) - tv.VerifyChild( - ifPath+"/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses/address[ip=*]", - portIpAddrNInfo(ifName, portIpv4KeyPattern)) - tv.VerifyChild( - ifPath+"/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses/address[ip=*]", - portIpAddrNInfo(ifName, portIpv6KeyPattern)) - }) - } - - for _, ifName := range []string{"*", "Ethernet123"} { - tcPrefix := fmt.Sprintf("name=%s|", ifName) - ifPath := fmt.Sprintf("/openconfig-interfaces:interfaces/interface[name=%s]", ifName) - - t.Run(tcPrefix+"ifName", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/name") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/name", portConfigNInfo(ifName, `{}`)) - }) - - t.Run(tcPrefix+"config_container", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/config") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/config", portConfigNInfo(ifName, `{"": `+portConfigFields+`}`)) - }) - - t.Run(tcPrefix+"config_attr", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/config/mtu") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/config/mtu", portConfigNInfo(ifName, `{"": {"mtu": ""}}`)) - }) - - t.Run(tcPrefix+"eth_all", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/openconfig-if-ethernet:ethernet") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/openconfig-if-ethernet:ethernet", - portConfigNInfo(ifName, `{"config":`+portEthConfigFields+`, "state":`+portEthConfigFields+`}`)) - }) - - t.Run(tcPrefix+"eth_config", func(t *testing.T) { - p := ifPath + "/openconfig-if-ethernet:ethernet/config" - tv := testTranslateSubscribe(t, p) - tv.VerifyCount(1, 0) - tv.VerifyTarget(p, portConfigNInfo(ifName, `{"":`+portEthConfigFields+`}`)) - }) - - t.Run(tcPrefix+"eth_speed", func(t *testing.T) { - p := ifPath + "/openconfig-if-ethernet:ethernet/state/port-speed" - tv := testTranslateSubscribe(t, p) - tv.VerifyCount(1, 0) - tv.VerifyTarget(p, portConfigNInfo(ifName, `{"":{"speed": ""}}`)) - }) - - t.Run(tcPrefix+"state_container", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/state") - tv.VerifyCount(1, 1) - tv.VerifyTarget(ifPath+"/state", portStateNInfo(ifName, portStateAllFields)) - tv.VerifyChild(ifPath+"/state/counters", portCountersNInfo(ifName)) - }) - - t.Run(tcPrefix+"state_admin_status", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/state/admin-status") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/state/admin-status", portStateNInfo(ifName, `{"": {"admin_status": ""}}`)) - }) - - t.Run(tcPrefix+"state_counters", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/state/counters") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/state/counters", portCountersNInfo(ifName)) - }) - - t.Run(tcPrefix+"state_counters_attr", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/state/counters/in-octets") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ifPath+"/state/counters/in-octets", portCountersNInfo(ifName)) - }) - - ipv4List := ifPath + "/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses/address" - ipv6List := ifPath + "/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses/address" - - for _, p := range []string{"/subinterfaces", "/subinterfaces/subinterface[index=*]", "/subinterfaces/subinterface[index=0]"} { - t.Run(tcPrefix+"subif="+NewPathInfo(p).Var("index"), func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+p) - tv.VerifyCount(2, 0) - tv.VerifyTarget(ipv4List+"[ip=*]", portIpAddrNInfo(ifName, portIpv4KeyPattern)) - tv.VerifyTarget(ipv6List+"[ip=*]", portIpAddrNInfo(ifName, portIpv6KeyPattern)) - }) - } - - t.Run(tcPrefix+"invalid_subif", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/subinterfaces/subinterface[index=2]") - tv.VerifyCount(translErr, 0) - }) - - for _, p := range []string{"", "/addresses", "/addresses/address[ip=*]"} { - t.Run(tcPrefix+"ipv4", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4"+p) - tv.VerifyCount(1, 0) - tv.VerifyTarget(ipv4List+"[ip=*]", portIpAddrNInfo(ifName, portIpv4KeyPattern)) - }) - } - - t.Run(tcPrefix+"ipv4_specific", func(t *testing.T) { - tv := testTranslateSubscribe(t, ipv4List+"[ip=1.2.3.4]") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ipv4List+"[ip=1.2.3.4]", portIpAddrNInfo(ifName, "1.2.3.4/*")) - }) - - t.Run(tcPrefix+"ipv4_invalid", func(t *testing.T) { - tv := testTranslateSubscribe(t, ipv4List+"[ip=1234]") - tv.VerifyCount(translErr, 0) - }) - - for _, p := range []string{"", "/addresses", "/addresses/address[ip=*]"} { - t.Run(tcPrefix+"ipv6", func(t *testing.T) { - tv := testTranslateSubscribe(t, ifPath+"/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6"+p) - tv.VerifyCount(1, 0) - tv.VerifyTarget(ipv6List+"[ip=*]", portIpAddrNInfo(ifName, portIpv6KeyPattern)) - }) - } - - t.Run(tcPrefix+"ipv6_specific", func(t *testing.T) { - tv := testTranslateSubscribe(t, ipv6List+"[ip=1001:80::1]") - tv.VerifyCount(1, 0) - tv.VerifyTarget(ipv6List+"[ip=1001:80::1]", portIpAddrNInfo(ifName, "1001:80::1/*")) - }) - - t.Run(tcPrefix+"ipv6_invalid", func(t *testing.T) { - tv := testTranslateSubscribe(t, ipv6List+"[ip=1234abcd]") - tv.VerifyCount(translErr, 0) - }) - } -} - -const ( - portConfigFields = `{"description": "description", "admin_status": "enabled", "mtu": "mtu"}` - portEthConfigFields = `{"speed": "port-speed"}` - portStateAllFields = `{"": {"index": "ifindex", "admin_status": "enabled,admin-status", "oper_status": "oper-status", "description": "description", "mtu": "mtu"}}` - portConfigAllFields = `{"config": ` + portConfigFields + - `, "openconfig-if-ethernet:ethernet/config": ` + portEthConfigFields + - `, "openconfig-if-ethernet:ethernet/state": ` + portEthConfigFields + `}` - - portIpv4KeyPattern = "*.*.*.*/*" - portIpv6KeyPattern = "*:*/*" -) - -func portConfigNInfo(ifName, fieldsJson string) *notificationAppInfo { - return ¬ificationAppInfo{ - dbno: db.ConfigDB, - table: &db.TableSpec{Name: "PORT"}, - key: db.NewKey(ifName), - dbFldYgPathInfoList: parseFieldsJSON(fieldsJson), - isOnChangeSupported: true, - pType: OnChange, - } -} - -func portStateNInfo(ifName, fieldsJson string) *notificationAppInfo { - return ¬ificationAppInfo{ - dbno: db.ApplDB, - table: &db.TableSpec{Name: "PORT_TABLE"}, - key: db.NewKey(ifName), - dbFldYgPathInfoList: parseFieldsJSON(fieldsJson), - isOnChangeSupported: true, - pType: OnChange, - } -} - -func portCountersNInfo(ifName string) *notificationAppInfo { - fieldPattern := ifName - if ifName == "*" { - fieldPattern = countersMapFieldPattern - } - return ¬ificationAppInfo{ - dbno: db.CountersDB, - table: &db.TableSpec{Name: "COUNTERS_PORT_NAME_MAP"}, - key: db.NewKey(), - fieldScanPattern: fieldPattern, - isOnChangeSupported: false, - pType: Sample, - } -} - -func portIpAddrNInfo(ifName, ipAddr string) *notificationAppInfo { - return ¬ificationAppInfo{ - dbno: db.ConfigDB, - table: &db.TableSpec{Name: "INTERFACE"}, - key: db.NewKey(ifName, ipAddr), - isOnChangeSupported: true, - pType: OnChange, - } -} diff --git a/translib/sys_app.go b/translib/sys_app.go index 58b4b2f3c..a0a30a608 100644 --- a/translib/sys_app.go +++ b/translib/sys_app.go @@ -43,6 +43,13 @@ type SysApp struct { procTable map[uint64]dbEntry } +type reqType int + +type dbEntry struct { + op reqType + entry db.Value +} + func init() { log.Info("SysApp: Init called for System module") err := register("/openconfig-system:system", diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go new file mode 100644 index 000000000..a018a5441 --- /dev/null +++ b/translib/transformer/xfmr_intf.go @@ -0,0 +1,2271 @@ +////////////////////////////////////////////////////////////////////////// +// +// 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 ( + "errors" + "fmt" + "github.com/Azure/sonic-mgmt-common/translib/utils" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + + "inet.af/netaddr" + + "github.com/Azure/sonic-mgmt-common/translib/db" + "github.com/Azure/sonic-mgmt-common/translib/ocbinds" + "github.com/Azure/sonic-mgmt-common/translib/tlerr" + log "github.com/golang/glog" + "github.com/openconfig/ygot/ygot" +) + +func init() { + + XlateFuncBind("intf_table_xfmr", intf_table_xfmr) + + XlateFuncBind("YangToDb_intf_tbl_key_xfmr", YangToDb_intf_tbl_key_xfmr) + XlateFuncBind("DbToYang_intf_tbl_key_xfmr", DbToYang_intf_tbl_key_xfmr) + + XlateFuncBind("DbToYang_intf_admin_status_xfmr", DbToYang_intf_admin_status_xfmr) + + XlateFuncBind("YangToDb_intf_enabled_xfmr", YangToDb_intf_enabled_xfmr) + XlateFuncBind("DbToYang_intf_enabled_xfmr", DbToYang_intf_enabled_xfmr) + + XlateFuncBind("YangToDb_intf_subintfs_xfmr", YangToDb_intf_subintfs_xfmr) + XlateFuncBind("DbToYang_intf_subintfs_xfmr", DbToYang_intf_subintfs_xfmr) + + XlateFuncBind("YangToDb_subintf_ip_addr_key_xfmr", YangToDb_subintf_ip_addr_key_xfmr) + XlateFuncBind("DbToYang_subintf_ip_addr_key_xfmr", DbToYang_subintf_ip_addr_key_xfmr) + XlateFuncBind("YangToDb_intf_ip_addr_xfmr", YangToDb_intf_ip_addr_xfmr) + XlateFuncBind("DbToYang_intf_ip_addr_xfmr", DbToYang_intf_ip_addr_xfmr) + + XlateFuncBind("intf_subintfs_table_xfmr", intf_subintfs_table_xfmr) + XlateFuncBind("YangToDb_subif_index_xfmr", YangToDb_subif_index_xfmr) + XlateFuncBind("DbToYang_subif_index_xfmr", DbToYang_subif_index_xfmr) + XlateFuncBind("DbToYangPath_intf_ip_path_xfmr", DbToYangPath_intf_ip_path_xfmr) + XlateFuncBind("Subscribe_intf_ip_addr_xfmr", Subscribe_intf_ip_addr_xfmr) + + XlateFuncBind("YangToDb_subintf_ipv6_tbl_key_xfmr", YangToDb_subintf_ipv6_tbl_key_xfmr) + XlateFuncBind("DbToYang_subintf_ipv6_tbl_key_xfmr", DbToYang_subintf_ipv6_tbl_key_xfmr) + XlateFuncBind("YangToDb_ipv6_enabled_xfmr", YangToDb_ipv6_enabled_xfmr) + XlateFuncBind("DbToYang_ipv6_enabled_xfmr", DbToYang_ipv6_enabled_xfmr) + + XlateFuncBind("intf_post_xfmr", intf_post_xfmr) + XlateFuncBind("intf_pre_xfmr", intf_pre_xfmr) + +} + +const ( + PORT_ADMIN_STATUS = "admin_status" + PORTCHANNEL_TN = "PORTCHANNEL" +) + +const ( + PIPE = "|" + COLON = ":" + + ETHERNET = "Eth" + MGMT = "eth" + VLAN = "Vlan" + PORTCHANNEL = "PortChannel" + LOOPBACK = "Loopback" + VXLAN = "vtep" + MANAGEMENT = "Management" +) + +type TblData struct { + portTN string + memberTN string + intfTN string + keySep string +} + +type IntfTblData struct { + cfgDb TblData + appDb TblData + stateDb TblData +} + +var IntfTypeTblMap = map[E_InterfaceType]IntfTblData{ + IntfTypeEthernet: IntfTblData{ + cfgDb: TblData{portTN: "PORT", intfTN: "INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "PORT_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, + stateDb: TblData{portTN: "PORT_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, + }, + IntfTypeMgmt: IntfTblData{ + cfgDb: TblData{portTN: "MGMT_PORT", intfTN: "MGMT_INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "MGMT_PORT_TABLE", intfTN: "MGMT_INTF_TABLE", keySep: COLON}, + stateDb: TblData{portTN: "MGMT_PORT_TABLE", intfTN: "MGMT_INTERFACE_TABLE", keySep: PIPE}, + }, + IntfTypePortChannel: IntfTblData{ + cfgDb: TblData{portTN: "PORTCHANNEL", intfTN: "PORTCHANNEL_INTERFACE", memberTN: "PORTCHANNEL_MEMBER", keySep: PIPE}, + appDb: TblData{portTN: "LAG_TABLE", intfTN: "INTF_TABLE", keySep: COLON, memberTN: "LAG_MEMBER_TABLE"}, + stateDb: TblData{portTN: "LAG_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, + }, + IntfTypeVlan: IntfTblData{ + cfgDb: TblData{portTN: "VLAN", memberTN: "VLAN_MEMBER", intfTN: "VLAN_INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "VLAN_TABLE", memberTN: "VLAN_MEMBER_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, + }, + IntfTypeLoopback: IntfTblData{ + cfgDb: TblData{portTN: "LOOPBACK", intfTN: "LOOPBACK_INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "LOOPBACK_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, + }, + IntfTypeSubIntf: IntfTblData{ + cfgDb: TblData{portTN: "VLAN_SUB_INTERFACE", intfTN: "VLAN_SUB_INTERFACE", keySep: PIPE}, + appDb: TblData{portTN: "PORT_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, + stateDb: TblData{portTN: "PORT_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, + }, +} + +var dbIdToTblMap = map[db.DBNum][]string{ + db.ConfigDB: {"PORT", "MGMT_PORT", "VLAN", "PORTCHANNEL", "LOOPBACK", "VXLAN_TUNNEL", "VLAN_SUB_INTERFACE"}, + db.ApplDB: {"PORT_TABLE", "MGMT_PORT_TABLE", "VLAN_TABLE", "LAG_TABLE"}, + db.StateDB: {"PORT_TABLE", "MGMT_PORT_TABLE", "LAG_TABLE"}, +} + +type E_InterfaceType int64 + +const ( + IntfTypeUnset E_InterfaceType = 0 + IntfTypeEthernet E_InterfaceType = 1 + IntfTypeMgmt E_InterfaceType = 2 + IntfTypeVlan E_InterfaceType = 3 + IntfTypePortChannel E_InterfaceType = 4 + IntfTypeLoopback E_InterfaceType = 5 + IntfTypeVxlan E_InterfaceType = 6 + IntfTypeSubIntf E_InterfaceType = 7 +) + +type E_InterfaceSubType int64 + +const ( + IntfSubTypeUnset E_InterfaceSubType = 0 + IntfSubTypeVlanL2 E_InterfaceSubType = 1 + InterfaceSubTypeVlanL3 E_InterfaceSubType = 2 +) + +func getIntfTypeByName(name string) (E_InterfaceType, E_InterfaceSubType, error) { + + var err error + if strings.Contains(name, ".") { + if strings.HasPrefix(name, ETHERNET) || strings.HasPrefix(name, "Po") { + return IntfTypeSubIntf, IntfSubTypeUnset, err + } + } + if strings.HasPrefix(name, ETHERNET) { + return IntfTypeEthernet, IntfSubTypeUnset, err + } else { + err = errors.New("Interface name prefix not matched with supported types") + return IntfTypeUnset, IntfSubTypeUnset, err + } +} + +func getIntfsRoot(s *ygot.GoStruct) *ocbinds.OpenconfigInterfaces_Interfaces { + deviceObj := (*s).(*ocbinds.Device) + return deviceObj.Interfaces +} + +func getPortTableNameByDBId(intftbl IntfTblData, curDb db.DBNum) (string, error) { + + var tblName string + + switch curDb { + case db.ConfigDB: + tblName = intftbl.cfgDb.portTN + case db.ApplDB: + tblName = intftbl.appDb.portTN + case db.StateDB: + tblName = intftbl.stateDb.portTN + default: + tblName = intftbl.cfgDb.portTN + } + + return tblName, nil +} + +/* Perform action based on the operation and Interface type wrt Interface name key */ +/* It should handle only Interface name key xfmr operations */ +func performIfNameKeyXfmrOp(inParams *XfmrParams, requestUriPath *string, ifName *string, ifType E_InterfaceType, subintfid uint32) error { + var err error + switch inParams.oper { + case GET: + if ifType == IntfTypeSubIntf && subintfid == 0 { + errStr := "Invalid interface name: " + *ifName + log.Infof("Invalid interface name: %s for GET path: %v", *ifName, *requestUriPath) + err = tlerr.InvalidArgsError{Format: errStr} + return err + } + case DELETE: + if *requestUriPath == "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface" && subintfid != 0 { + return nil + } + + if *requestUriPath == "/openconfig-interfaces:interfaces/interface" { + switch ifType { + case IntfTypeEthernet: + err = validateIntfExists(inParams.d, IntfTypeTblMap[IntfTypeEthernet].cfgDb.portTN, *ifName) + if err != nil { + // Not returning error from here since mgmt infra will return "Resource not found" error in case of non existence entries + return nil + } + errStr := "Physical Interface: " + *ifName + " cannot be deleted" + err = tlerr.InvalidArgsError{Format: errStr} + return err + default: + errStr := "Invalid interface for delete:" + *ifName + log.Error(errStr) + return tlerr.InvalidArgsError{Format: errStr} + } + + } + case CREATE: + fallthrough + case UPDATE, REPLACE: + if ifType == IntfTypeEthernet { + err = validateIntfExists(inParams.d, IntfTypeTblMap[IntfTypeEthernet].cfgDb.portTN, *ifName) + if err != nil { // Invalid Physical interface + errStr := "Interface " + *ifName + " cannot be configured." + return tlerr.InvalidArgsError{Format: errStr} + } + if inParams.oper == REPLACE { + if strings.Contains(*requestUriPath, "/openconfig-interfaces:interfaces/interface") { + if strings.Contains(*requestUriPath, "openconfig-if-ethernet:ethernet/openconfig-vlan:switched-vlan") || + strings.Contains(*requestUriPath, "mapped-vlans") { + log.Infof("allow replace operation for switched-vlan") + } else { + // OC interfaces yang does not have attributes to set Physical interface critical attributes like speed, alias, lanes, index. + // Replace/PUT request without the critical attributes would end up in deletion of the same in PORT table, which cannot be allowed. + // Hence block the Replace/PUT request for Physical interfaces alone. + err_str := "Replace/PUT request not allowed for Physical interfaces" + return tlerr.NotSupported(err_str) + } + } + } + } + } + return err +} + +/* Validate whether intf exists in DB */ +func validateIntfExists(d *db.DB, intfTs string, ifName string) error { + if len(ifName) == 0 { + return errors.New("Length of Interface name is zero") + } + + entry, err := d.GetEntry(&db.TableSpec{Name: intfTs}, db.Key{Comp: []string{ifName}}) + if err != nil || !entry.IsPopulated() { + errStr := "Invalid Interface:" + ifName + if log.V(3) { + log.Error(errStr) + } + return tlerr.InvalidArgsError{Format: errStr} + } + return nil +} + +func getMemTableNameByDBId(intftbl IntfTblData, curDb db.DBNum) (string, error) { + + var tblName string + + switch curDb { + case db.ConfigDB: + tblName = intftbl.cfgDb.memberTN + case db.ApplDB: + tblName = intftbl.appDb.memberTN + case db.StateDB: + tblName = intftbl.stateDb.memberTN + default: + tblName = intftbl.cfgDb.memberTN + } + + return tblName, nil +} + +var intf_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string, error) { + var tblList []string + var err error + + pathInfo := NewPathInfo(inParams.uri) + + targetUriPath := pathInfo.YangPath + targetUriXpath, _, _ := XfmrRemoveXPATHPredicates(targetUriPath) + + ifName := pathInfo.Var("name") + if ifName == "" { + log.Info("TableXfmrFunc - intf_table_xfmr Intf key is not present") + + if _, ok := dbIdToTblMap[inParams.curDb]; !ok { + if log.V(3) { + log.Info("TableXfmrFunc - intf_table_xfmr db id entry not present") + } + return tblList, errors.New("Key not present") + } else { + return dbIdToTblMap[inParams.curDb], nil + } + } + ifName = *(&ifName) + + idx := pathInfo.Var("index") + var i32 uint32 + i32 = 0 + if idx != "" { + i64, _ := strconv.ParseUint(idx, 10, 32) + i32 = uint32(i64) + } + + intfType, _, ierr := getIntfTypeByName(ifName) + if intfType == IntfTypeUnset || ierr != nil { + return tblList, errors.New("Invalid interface type IntfTypeUnset") + } + intTbl := IntfTypeTblMap[intfType] + if log.V(3) { + log.Info("TableXfmrFunc - targetUriPath : ", targetUriPath) + log.Info("TableXfmrFunc - targetUriXpath : ", targetUriXpath) + } + + if inParams.oper == DELETE && (targetUriXpath == "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4" || + targetUriXpath == "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6") { + errStr := "DELETE operation not allowed on this container" + return tblList, tlerr.NotSupportedError{AppTag: "invalid-value", Path: "", Format: errStr} + + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/config") { + if IntfTypeVxlan != intfType { + tblList = append(tblList, intTbl.cfgDb.portTN) + } + } else if intfType != IntfTypeEthernet && intfType != IntfTypeMgmt && + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet") { + //Checking interface type at container level, if not Ethernet type return nil + return nil, nil + } else if intfType != IntfTypePortChannel && + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-aggregate:aggregation") { + //Checking interface type at container level, if not PortChannel type return nil + return nil, nil + } else if intfType != IntfTypeVlan && + strings.HasPrefix(targetUriPath, "openconfig-interfaces:interfaces/interface/openconfig-vlan:routed-vlan") { + //Checking interface type at container level, if not Vlan type return nil + return nil, nil + } else if intfType != IntfTypeVxlan && + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-vxlan:vxlan-if") { + //Checking interface type at container level, if not Vxlan type return nil + return nil, nil + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/state/counters") { + tblList = append(tblList, "NONE") + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/ethernet/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/state") { + tblList = append(tblList, intTbl.appDb.portTN) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/config") { + if i32 > 0 { + tblList = append(tblList, "VLAN_SUB_INTERFACE") + } else { + tblList = append(tblList, intTbl.cfgDb.intfTN) + } + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/state") { + tblList = append(tblList, intTbl.appDb.intfTN) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses") { + tblList = append(tblList, intTbl.cfgDb.intfTN) + } else if inParams.oper == GET && strings.HasPrefix(targetUriXpath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/neighbors") || + strings.HasPrefix(targetUriXpath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/neighbors") { + tblList = append(tblList, "NONE") + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/ethernet") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet") { + if inParams.oper != DELETE { + tblList = append(tblList, intTbl.cfgDb.portTN) + } + } else if targetUriPath == "/openconfig-interfaces:interfaces/interface" { + tblList = append(tblList, intTbl.cfgDb.portTN) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface") { + if inParams.oper != DELETE { + tblList = append(tblList, intTbl.cfgDb.portTN) + } + } else { + err = errors.New("Invalid URI") + } + + if log.V(3) { + log.Infof("TableXfmrFunc - Uri: (%v), targetUriPath: %s, tblList: (%v)", inParams.uri, targetUriPath, tblList) + } + + return tblList, err +} + +var YangToDb_intf_tbl_key_xfmr KeyXfmrYangToDb = func(inParams XfmrParams) (string, error) { + var err error + + pathInfo := NewPathInfo(inParams.uri) + reqpathInfo := NewPathInfo(inParams.requestUri) + requestUriPath := reqpathInfo.YangPath + + log.Infof("YangToDb_intf_tbl_key_xfmr: inParams.uri: %s, pathInfo: %s, inParams.requestUri: %s", inParams.uri, pathInfo, requestUriPath) + + ifName := pathInfo.Var("name") + idx := reqpathInfo.Var("index") + var i32 uint32 + i32 = 0 + + if idx != "" { + i64, _ := strconv.ParseUint(idx, 10, 32) + i32 = uint32(i64) + } + + if ifName == "*" { + return ifName, nil + } + + if ifName != "" { + log.Info("YangToDb_intf_tbl_key_xfmr: ifName: ", ifName) + intfType, _, ierr := getIntfTypeByName(ifName) + if ierr != nil { + log.Errorf("Extracting Interface type for Interface: %s failed!", ifName) + return "", tlerr.New(ierr.Error()) + } + err = performIfNameKeyXfmrOp(&inParams, &requestUriPath, &ifName, intfType, i32) + if err != nil { + return "", tlerr.InvalidArgsError{Format: err.Error()} + } + } + return ifName, err +} + +var DbToYang_intf_tbl_key_xfmr KeyXfmrDbToYang = func(inParams XfmrParams) (map[string]interface{}, error) { + if log.V(3) { + log.Info("Entering DbToYang_intf_tbl_key_xfmr") + } + res_map := make(map[string]interface{}) + log.Info("DbToYang_intf_tbl_key_xfmr: Interface Name = ", inParams.key) + res_map["name"] = inParams.key + return res_map, nil +} + +var DbToYang_intf_admin_status_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + + data := (*inParams.dbDataMap)[inParams.curDb] + + intfType, _, ierr := getIntfTypeByName(inParams.key) + if intfType == IntfTypeUnset || ierr != nil { + log.Info("DbToYang_intf_admin_status_xfmr - Invalid interface type IntfTypeUnset") + return result, errors.New("Invalid interface type IntfTypeUnset") + } + if IntfTypeVxlan == intfType { + return result, nil + } + intTbl := IntfTypeTblMap[intfType] + + tblName, _ := getPortTableNameByDBId(intTbl, inParams.curDb) + if _, ok := data[tblName]; !ok { + log.Info("DbToYang_intf_admin_status_xfmr table not found : ", tblName) + return result, errors.New("table not found : " + tblName) + } + pTbl := data[tblName] + if _, ok := pTbl[inParams.key]; !ok { + log.Info("DbToYang_intf_admin_status_xfmr Interface not found : ", inParams.key) + return result, errors.New("Interface not found : " + inParams.key) + } + prtInst := pTbl[inParams.key] + adminStatus, ok := prtInst.Field[PORT_ADMIN_STATUS] + var status ocbinds.E_OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus + if ok { + if adminStatus == "up" { + status = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UP + } else { + status = ocbinds.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_DOWN + } + result["admin-status"] = ocbinds.E_OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus.ΛMap(status)["E_OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus"][int64(status)].Name + } else { + log.Info("Admin status field not found in DB") + } + + return result, err +} + +var YangToDb_intf_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[string]string, error) { + res_map := make(map[string]string) + var ifName string + intfsObj := getIntfsRoot(inParams.ygRoot) + if intfsObj == nil || len(intfsObj.Interface) < 1 { + return res_map, nil + } else { + for infK := range intfsObj.Interface { + ifName = infK + } + } + intfType, _, _ := getIntfTypeByName(ifName) + if IntfTypeVxlan == intfType { + return res_map, nil + } + enabled, _ := inParams.param.(*bool) + var enStr string + if *enabled { + enStr = "up" + } else { + enStr = "down" + } + res_map[PORT_ADMIN_STATUS] = enStr + + return res_map, nil +} + +var DbToYang_intf_enabled_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + var err error + result := make(map[string]interface{}) + + data := (*inParams.dbDataMap)[inParams.curDb] + + intfType, _, ierr := getIntfTypeByName(inParams.key) + if intfType == IntfTypeUnset || ierr != nil { + log.Info("DbToYang_intf_enabled_xfmr - Invalid interface type IntfTypeUnset") + return result, errors.New("Invalid interface type IntfTypeUnset") + } + if IntfTypeVxlan == intfType { + return result, nil + } + + intTbl := IntfTypeTblMap[intfType] + + tblName, _ := getPortTableNameByDBId(intTbl, inParams.curDb) + if _, ok := data[tblName]; !ok { + log.Info("DbToYang_intf_enabled_xfmr table not found : ", tblName) + return result, errors.New("table not found : " + tblName) + } + + pTbl := data[tblName] + if _, ok := pTbl[inParams.key]; !ok { + log.Info("DbToYang_intf_enabled_xfmr Interface not found : ", inParams.key) + return result, errors.New("Interface not found : " + inParams.key) + } + prtInst := pTbl[inParams.key] + adminStatus, ok := prtInst.Field[PORT_ADMIN_STATUS] + if ok { + if adminStatus == "up" { + result["enabled"] = true + } else { + result["enabled"] = false + } + } else { + log.Info("Admin status field not found in DB") + } + return result, err +} + +var intf_post_xfmr PostXfmrFunc = func(inParams XfmrParams) (map[string]map[string]db.Value, error) { + + requestUriPath := (NewPathInfo(inParams.requestUri)).YangPath + retDbDataMap := (*inParams.dbDataMap)[inParams.curDb] + log.Info("Entering intf_post_xfmr") + log.Info(requestUriPath) + xpath, _, _ := XfmrRemoveXPATHPredicates(inParams.requestUri) + + if inParams.oper == DELETE { + + err_str := "Delete not allowed at this container" + /* Preventing delete at IPv6 config level*/ + if xpath == "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/config" { + log.Info("In interface Post transformer for DELETE op ==> URI : ", inParams.requestUri) + return retDbDataMap, tlerr.NotSupported(err_str) + } + + /* For delete request and for fields with default value, transformer adds subOp map with update operation (to update with default value). + So, adding code to clear the update SubOp map for delete operation to go through for the following requestUriPath */ + if xpath == "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/config/enabled" { + if len(inParams.subOpDataMap) > 0 { + dbMap := make(map[string]map[string]db.Value) + if inParams.subOpDataMap[4] != nil && (*inParams.subOpDataMap[4])[db.ConfigDB] != nil { + (*inParams.subOpDataMap[4])[db.ConfigDB] = dbMap + } + log.Info("intf_post_xfmr inParams.subOpDataMap :", inParams.subOpDataMap) + } + } + } else if inParams.oper == UPDATE { + if replace, ok := inParams.subOpDataMap[REPLACE]; ok { + if (*replace)[db.ConfigDB] != nil { + if portTable, ok := (*replace)[db.ConfigDB]["PORT"]; ok { + for key := range portTable { + delete(inParams.yangDefValMap["PORT"], key) + } + } + } + } + } + return retDbDataMap, nil +} + +var intf_pre_xfmr PreXfmrFunc = func(inParams XfmrParams) error { + var err error + if inParams.oper == DELETE || inParams.oper == REPLACE { + requestUriPath := (NewPathInfo(inParams.requestUri)).YangPath + if log.V(3) { + log.Info("intf_pre_xfmr:- Request URI path = ", requestUriPath) + } + errStr := "Delete operation not supported for this path - " + if inParams.oper == REPLACE { + errStr = "Replace operation not supported for this path - " + } + switch requestUriPath { + case "/openconfig-interfaces:interfaces": + errStr += requestUriPath + return tlerr.InvalidArgsError{Format: errStr} + case "/openconfig-interfaces:interfaces/interface": + pathInfo := NewPathInfo(inParams.uri) + if len(pathInfo.Vars) == 0 { + errStr += requestUriPath + return tlerr.InvalidArgsError{Format: errStr} + } + } + } + return err +} + +func populateVlanSubIntfTblKeys(inParams XfmrParams) error { + var key string + + (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"] = make(map[string]db.Value) + mapIntfKeys, _ := inParams.d.GetKeys(&db.TableSpec{Name: "VLAN_SUB_INTERFACE"}) + if len(mapIntfKeys) > 0 { + for _, intfKey := range mapIntfKeys { + key = intfKey.Get(0) + key = *(&key) + if _, ok := (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"][key]; !ok { + (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"][key] = db.Value{Field: make(map[string]string)} + (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"][key].Field["NULL"] = "NULL" + } + } + } + + if log.V(3) { + log.Infof("populateVlanSubIntfTblKeys, configDB dbdataMap[\"VLAN_SUB_INTERFACE\"]: %v ", (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"]) + } + + return nil +} + +var intf_subintfs_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string, error) { + var tblList []string + + pathInfo := NewPathInfo(inParams.uri) + ifName := pathInfo.Var("name") + idx := pathInfo.Var("index") + + if inParams.oper == SUBSCRIBE { + var _intfTypeList []E_InterfaceType + + _addSubIntfToList := func() { + if idx == "*" || idx != "0" { + _intfTypeList = append(_intfTypeList, IntfTypeSubIntf) + } + } + + if ifName == "*" { + _intfTypeList = append(_intfTypeList, IntfTypeEthernet, IntfTypeMgmt, IntfTypePortChannel, IntfTypeLoopback) + _addSubIntfToList() + } else { + _ifType, _, _err := getIntfTypeByName(ifName) + if _ifType == IntfTypeUnset || _err != nil { + return tblList, errors.New("Invalid interface type IntfTypeUnset") + } + if IntfTypeVlan == _ifType || IntfTypeVxlan == _ifType { + return tblList, nil + } + _intfTypeList = append(_intfTypeList, _ifType) + _addSubIntfToList() + } + + for _, _ifType := range _intfTypeList { + _intfTblName, _ := getIntfTableNameByDBId(IntfTypeTblMap[_ifType], inParams.curDb) + tblList = append(tblList, _intfTblName) + } + + log.V(3).Info("intf_subintfs_table_xfmr: URI: ", inParams.uri, " OP:", inParams.oper, " ifName:", ifName, " idx:", idx, " tblList:", tblList) + return tblList, nil + } + + //if GET at top level, populate the VLAN_SUB_INTERFACE table with keys and store the flag to txCache + val, present := inParams.txCache.Load("vlan_sub_intf_tbl_keys_read") + reqPathInfo := NewPathInfo(inParams.requestUri) + requestUriPath := reqPathInfo.YangPath + var reqUriIfName string = reqPathInfo.Var("name") + if inParams.oper == GET && (requestUriPath == "/openconfig-interfaces:interfaces" || + requestUriPath == "/openconfig-interfaces:interfaces/interface") && reqUriIfName == "" { + if !present || val != true { + if inParams.dbDataMap != nil { + populateVlanSubIntfTblKeys(inParams) + inParams.txCache.Store("vlan_sub_intf_tbl_keys_read", true) + val = true + log.Info("intf_subintfs_table_xfmr, cached vlan_sub_intf_tbl_keys_read") + } + } + } + + if idx == "" { + if inParams.oper == GET || inParams.oper == DELETE { + if inParams.dbDataMap != nil { + (*inParams.dbDataMap)[db.ConfigDB]["SUBINTF_TBL"] = make(map[string]db.Value) + (*inParams.dbDataMap)[db.ConfigDB]["SUBINTF_TBL"]["0"] = db.Value{Field: make(map[string]string)} + tblList = append(tblList, "SUBINTF_TBL") + tblList = append(tblList, "VLAN_SUB_INTERFACE") + } + } + log.Info("intf_subintfs_table_xfmr - Subinterface get operation ") + } else { + if idx == "0" { + if inParams.dbDataMap != nil { + (*inParams.dbDataMap)[db.ConfigDB]["SUBINTF_TBL"] = make(map[string]db.Value) + (*inParams.dbDataMap)[db.ConfigDB]["SUBINTF_TBL"]["0"] = db.Value{Field: make(map[string]string)} + (*inParams.dbDataMap)[db.ConfigDB]["SUBINTF_TBL"]["0"].Field["NULL"] = "NULL" + } + tblList = append(tblList, "SUBINTF_TBL") + } else { + if inParams.dbDataMap != nil { + (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"] = make(map[string]db.Value) + if val == true { + //reset cached flag + inParams.txCache.Store("vlan_sub_intf_tbl_keys_read", false) + log.Info("intf_subintfs_table_xfmr, reset vlan_sub_intf_tbl_keys_read cache") + } + } + tblList = append(tblList, "VLAN_SUB_INTERFACE") + *inParams.isVirtualTbl = false + } + if log.V(3) { + log.Info("intf_subintfs_table_xfmr - Subinterface get operation ") + } + } + + return tblList, nil +} + +var YangToDb_intf_subintfs_xfmr KeyXfmrYangToDb = func(inParams XfmrParams) (string, error) { + var subintf_key string + var err error + + log.Info("YangToDb_intf_subintfs_xfmr - inParams.uri ", inParams.uri) + + pathInfo := NewPathInfo(inParams.uri) + ifName := pathInfo.Var("name") + if ifName == "*" { + return ifName, nil + } + + intfType, _, ierr := getIntfTypeByName(ifName) + if intfType == IntfTypeUnset || ierr != nil { + return ifName, errors.New("Invalid interface type IntfTypeUnset") + } + if IntfTypeVlan == intfType { + log.Info("YangToDb_intf_subintfs_xfmr - IntfTypeVlan") + return ifName, nil + } + + idx := pathInfo.Var("index") + + if idx != "0" && idx != "*" && idx != "" { + subintf_key = ifName + "." + idx + } else { /* For get 0 index case & subscribe index * case */ + subintf_key = idx + } + + log.Info("YangToDb_intf_subintfs_xfmr - return subintf_key ", subintf_key) + return subintf_key, err +} + +var DbToYang_intf_subintfs_xfmr KeyXfmrDbToYang = func(inParams XfmrParams) (map[string]interface{}, error) { + + if log.V(3) { + log.Info("Entering DbToYang_intf_subintfs_xfmr") + } + var idx string + + if strings.Contains(inParams.key, ".") { + key_split := strings.Split(inParams.key, ".") + idx = key_split[1] + } else { + idx = inParams.key + } + + rmap := make(map[string]interface{}) + var err error + i64, _ := strconv.ParseUint(idx, 10, 32) + rmap["index"] = i64 + + log.Info("DbToYang_intf_subintfs_xfmr rmap ", rmap) + return rmap, err +} + +var YangToDb_subintf_ip_addr_key_xfmr KeyXfmrYangToDb = func(inParams XfmrParams) (string, error) { + if log.V(3) { + log.Info("Entering YangToDb_subintf_ip_addr_key_xfmr") + } + var err error + var inst_key string + pathInfo := NewPathInfo(inParams.uri) + inst_key = pathInfo.Var("ip") + log.Infof("URI:%v Interface IP:%v", inParams.uri, inst_key) + return inst_key, err +} +var DbToYang_subintf_ip_addr_key_xfmr KeyXfmrDbToYang = func(inParams XfmrParams) (map[string]interface{}, error) { + if log.V(3) { + log.Info("Entering DbToYang_subintf_ip_addr_key_xfmr") + } + rmap := make(map[string]interface{}) + return rmap, nil +} + +var YangToDb_subif_index_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[string]string, error) { + res_map := make(map[string]string) + var err error + + pathInfo := NewPathInfo(inParams.uri) + uriIfName := pathInfo.Var("name") + log.Info(uriIfName) + ifName := uriIfName + + res_map["parent"] = ifName + + log.Info("YangToDb_subif_index_xfmr: res_map:", res_map) + return res_map, err +} + +var DbToYang_subif_index_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + res_map := make(map[string]interface{}) + + pathInfo := NewPathInfo(inParams.uri) + id := pathInfo.Var("index") + log.Info("DbToYang_subif_index_xfmr: Sub-interface Index = ", id) + i64, _ := strconv.ParseUint(id, 10, 32) + res_map["index"] = i64 + return res_map, nil +} + +var DbToYangPath_intf_ip_path_xfmr PathXfmrDbToYangFunc = func(params XfmrDbToYgPathParams) error { + ifRoot := "/openconfig-interfaces:interfaces/interface" + subIf := ifRoot + "/subinterfaces/subinterface" + dbKey := "" + + log.Info("DbToYangPath_intf_ip_path_xfmr: params: ", params) + + uiName := ¶ms.tblKeyComp[0] + ifParts := strings.Split(*uiName, ".") + + params.ygPathKeys[ifRoot+"/name"] = ifParts[0] + + if params.tblName == "INTERFACE" || params.tblName == "VLAN_INTERFACE" || + params.tblName == "INTF_TABLE" || params.tblName == "MGMT_INTERFACE" || + params.tblName == "VLAN_SUB_INTERFACE" || params.tblName == "MGMT_INTF_TABLE" || + params.tblName == "PORTCHANNEL_INTERFACE" || params.tblName == "LOOPBACK_INTERFACE" { + + addrPath := "/openconfig-if-ip:ipv4/addresses/address/ip" + + /* For APPL_DB IPv6 case, addr is split [fe80 56bf 64ff feba 3bc0/64] instead of + [fe80::56bf:64ff:feba:3bc0/64] + Handle this case + */ + dbKey = strings.Join(params.tblKeyComp[1:], ":") + + if len(params.tblKeyComp) > 2 || strings.Contains(dbKey, ":") { + addrPath = "/openconfig-if-ip:ipv6/addresses/address/ip" + } + + ipKey := strings.Split(dbKey, "/") + + if strings.HasPrefix(params.tblKeyComp[0], "Vlan") { + return nil + } else { + if len(ifParts) > 1 { + params.ygPathKeys[subIf+"/index"] = ifParts[1] + } else { + params.ygPathKeys[subIf+"/index"] = "0" + } + params.ygPathKeys[subIf+addrPath] = ipKey[0] + } + } + + log.Infof("DbToYangPath_intf_ip_path_xfmr: tblName:%v dbKey:[%v] params.ygPathKeys: %v", params.tblName, dbKey, params.ygPathKeys) + return nil +} + +/* Get interface to IP mapping for all interfaces in the given table */ +func getCachedAllIntfIpMap(dbCl *db.DB, tblName string, ipv4 bool, ipv6 bool, ip string, tblPattern *db.Table) (map[string]map[string]db.Value, error) { + var err error + all := true + intfIpMap := make(map[string]map[string]db.Value) + if !ipv4 || !ipv6 { + all = false + } + log.V(3).Info("Inside getCachedAllIntfIpMap: Get Interface IP Info from table cache to Internal DS") + + //Get keys from tblPattern + keys, err := tblPattern.GetKeys() + if err != nil { + return intfIpMap, err + } + + for _, key := range keys { + ifName := key.Get(0) + intfType, _, ierr := getIntfTypeByName(ifName) + if intfType == IntfTypeUnset || ierr != nil { + continue + } + + if !all { + ipB, _, _ := parseCIDR(key.Get(1)) + if (validIPv4(ipB.String()) && (!ipv4)) || + (validIPv6(ipB.String()) && (!ipv6)) { + continue + } + if ip != "" { + if ipB.String() != ip { + continue + } + } + } + + ipInfo, _ := tblPattern.GetEntry(db.Key{Comp: []string{ifName, key.Get(1)}}) + + if _, ok := intfIpMap[ifName]; !ok { + intfIpMap[ifName] = make(map[string]db.Value) + } + + intfIpMap[ifName][key.Get(1)] = ipInfo + } + return intfIpMap, err +} + +func handleAllIntfIPGetForTable(inParams XfmrParams, tblName string, isAppDb bool) error { + var err error + intfsObj := getIntfsRoot(inParams.ygRoot) + var intfObj *ocbinds.OpenconfigInterfaces_Interfaces_Interface + + var tblPattern db.Table + + currDb := inParams.dbs[db.ConfigDB] + if isAppDb { + currDb = inParams.dbs[db.ApplDB] + } + + dbTbl := db.TableSpec{Name: tblName, CompCt: 2} + keyPattern := db.Key{Comp: []string{"*", "*"}} + tblPattern, err = currDb.GetTablePattern(&dbTbl, keyPattern) + + if err != nil { + log.Error("handleAllIntfIPGetForTable: GetTablePattern() returns err: %v", err) + return nil + } + + var intfIpMap map[string]map[string]db.Value + if isAppDb { + intfIpMap, err = getCachedAllIntfIpMap(inParams.dbs[db.ApplDB], tblName, true, true, "", &tblPattern) + } else { + intfIpMap, err = getCachedAllIntfIpMap(inParams.dbs[db.ConfigDB], tblName, true, true, "", &tblPattern) + } + + if log.V(3) { + log.Infof("handleAllIntfIPGetForTable, tbl: %v, intfIpMap: %v", tblName, intfIpMap) + } + + if len(intfIpMap) == 0 { + return nil + } + + i32 := uint32(0) + + // YGOT filling + for intfName, ipMapDB := range intfIpMap { + if strings.HasPrefix(intfName, "Vlan") { + continue + } + + var subIdxStr string + var name string + if strings.Contains(intfName, ".") { + intfLongName := *(&intfName) + parts := strings.Split(intfLongName, ".") + name = *(&parts[0]) + subIdxStr = parts[1] + tmpIdx, _ := strconv.Atoi(subIdxStr) + i32 = uint32(tmpIdx) + } else { + name = *(&intfName) + } + + if intfsObj != nil && intfsObj.Interface != nil && len(intfsObj.Interface) > 0 { + var ok bool = false + if intfObj, ok = intfsObj.Interface[name]; !ok { + intfObj, _ = intfsObj.NewInterface(name) + } + ygot.BuildEmptyTree(intfObj) + if intfObj.Subinterfaces == nil { + ygot.BuildEmptyTree(intfObj.Subinterfaces) + } + } else { + ygot.BuildEmptyTree(intfsObj) + intfObj, _ = intfsObj.NewInterface(name) + ygot.BuildEmptyTree(intfObj) + } + + if log.V(3) { + log.Infof("handleAllIntfIPGetForTable, intfName: %v, name: %v, subidx: %v, ipmap: %v", intfName, name, i32, ipMapDB) + } + + if isAppDb { + convertIpMapToOC(ipMapDB, intfObj, true, i32) + } else { + convertIpMapToOC(ipMapDB, intfObj, false, i32) + } + } + return nil +} + +// ValidateIntfProvisionedForRelay helper function to validate IP address deletion if DHCP relay is provisioned +func ValidateIntfProvisionedForRelay(d *db.DB, ifName string, prefixIp string, entry *db.Value) (bool, error) { + var tblList string + + intfType, _, ierr := getIntfTypeByName(ifName) + if intfType == IntfTypeUnset || ierr != nil { + log.Info("ValidateIntfProvisionedForRelay - Invalid interface type IntfTypeUnset") + return false, errors.New("Invalid InterfaceType") + } + + // get all the IP addresses on this interface, refer to the intf table name + intTbl := IntfTypeTblMap[intfType] + tblList = intTbl.cfgDb.intfTN + + // for VLAN - DHCP info is stored in the VLAN Table + if intfType == IntfTypeVlan { + tblList = intTbl.cfgDb.portTN + } + + if entry == nil || intfType == IntfTypeVlan { + ent, dbErr := d.GetEntry(&db.TableSpec{Name: tblList}, db.Key{Comp: []string{ifName}}) + entry = &ent + if dbErr != nil { + log.Warning("Failed to read entry from config DB, " + tblList + " " + ifName) + return false, nil + } + } + + //check if dhcp_sever is provisioned for ipv4 + if strings.Contains(prefixIp, ".") || strings.Contains(prefixIp, "ipv4") { + log.V(2).Info("ValidateIntfProvisionedForRelay - IPv4Check") + log.V(2).Info(entry) + if len(entry.Field["dhcp_servers@"]) > 0 { + return true, nil + } + //} else if (strings.Contains(prefixIp, ":") && numIpv6 < 2) || strings.Contains(prefixIp, "ipv6") { + } else if (strings.Contains(prefixIp, ":")) || strings.Contains(prefixIp, "ipv6") { + //check if dhcpv6_sever is provisioned for ipv6 + log.V(2).Info("ValidateIntfProvisionedForRelay - IPv6Check") + log.V(2).Info(entry) + if len(entry.Field["dhcpv6_servers@"]) > 0 { + return true, nil + } + } + return false, nil +} + +func handleIntfIPGetByTargetURI(inParams XfmrParams, targetUriPath string, ifName string, intfObj *ocbinds.OpenconfigInterfaces_Interfaces_Interface) error { + var ipMap map[string]db.Value + var err error + + pathInfo := NewPathInfo(inParams.uri) + ipAddr := pathInfo.Var("ip") + idx := pathInfo.Var("index") + i32 := uint32(0) + if idx != "0" { + ifName = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&ifName, &idx) + i64, _ := strconv.ParseUint(idx, 10, 32) + i32 = uint32(i64) + } + intfType, _, ierr := getIntfTypeByName(ifName) + if intfType == IntfTypeUnset || ierr != nil { + errStr := "Invalid interface type IntfTypeUnset" + log.Info("YangToDb_intf_subintf_ip_xfmr : uri:" + inParams.uri + ": " + errStr) + return errors.New(errStr) + } + intTbl := IntfTypeTblMap[intfType] + + if len(ipAddr) > 0 { + // Check if the given IP is configured on interface + keyPattern := ifName + ":" + ipAddr + "/*" + ipKeys, err := inParams.dbs[db.ApplDB].GetKeysByPattern(&db.TableSpec{Name: intTbl.appDb.intfTN}, keyPattern) + if err != nil || len(ipKeys) == 0 { + return tlerr.NotFound("Resource not found") + } + } + + if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses/address/config") { + ipMap, err = getIntfIpByName(inParams.dbs[db.ConfigDB], intTbl.cfgDb.intfTN, ifName, true, false, ipAddr) + log.Info("handleIntfIPGetByTargetURI : ipv4 config ipMap - : ", ipMap) + convertIpMapToOC(ipMap, intfObj, false, i32) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses/address/config") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/config") { + ipMap, err = getIntfIpByName(inParams.dbs[db.ConfigDB], intTbl.cfgDb.intfTN, ifName, false, true, ipAddr) + log.Info("handleIntfIPGetByTargetURI : ipv6 config ipMap - : ", ipMap) + convertIpMapToOC(ipMap, intfObj, false, i32) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses/address/state") { + ipMap, err = getIntfIpByName(inParams.dbs[db.ApplDB], intTbl.appDb.intfTN, ifName, true, false, ipAddr) + log.Info("handleIntfIPGetByTargetURI : ipv4 state ipMap - : ", ipMap) + convertIpMapToOC(ipMap, intfObj, true, i32) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses/address/state") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/state") { + ipMap, err = getIntfIpByName(inParams.dbs[db.ApplDB], intTbl.appDb.intfTN, ifName, false, true, ipAddr) + log.Info("handleIntfIPGetByTargetURI : ipv6 state ipMap - : ", ipMap) + convertIpMapToOC(ipMap, intfObj, true, i32) + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses") { + ipMap, err = getIntfIpByName(inParams.dbs[db.ConfigDB], intTbl.cfgDb.intfTN, ifName, true, false, ipAddr) + if err == nil { + log.Info("handleIntfIPGetByTargetURI : ipv4 config ipMap - : ", ipMap) + convertIpMapToOC(ipMap, intfObj, false, i32) + } + ipMap, err = getIntfIpByName(inParams.dbs[db.ApplDB], intTbl.appDb.intfTN, ifName, true, false, ipAddr) + if err == nil { + log.Info("handleIntfIPGetByTargetURI : ipv4 state ipMap - : ", ipMap) + convertIpMapToOC(ipMap, intfObj, true, i32) + } + } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses") || + strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses") { + ipMap, err = getIntfIpByName(inParams.dbs[db.ConfigDB], intTbl.cfgDb.intfTN, ifName, false, true, ipAddr) + if err == nil { + log.Info("handleIntfIPGetByTargetURI : ipv6 config ipMap - : ", ipMap) + convertIpMapToOC(ipMap, intfObj, false, i32) + } + ipMap, err = getIntfIpByName(inParams.dbs[db.ApplDB], intTbl.appDb.intfTN, ifName, false, true, ipAddr) + if err == nil { + log.Info("handleIntfIPGetByTargetURI : ipv6 state ipMap - : ", ipMap) + convertIpMapToOC(ipMap, intfObj, true, i32) + } + } + return err +} +func convertIpMapToOC(intfIpMap map[string]db.Value, ifInfo *ocbinds.OpenconfigInterfaces_Interfaces_Interface, isState bool, subintfid uint32) error { + var subIntf *ocbinds.OpenconfigInterfaces_Interfaces_Interface_Subinterfaces_Subinterface + var err error + + if _, ok := ifInfo.Subinterfaces.Subinterface[subintfid]; !ok { + _, err = ifInfo.Subinterfaces.NewSubinterface(subintfid) + if err != nil { + log.Error("Creation of subinterface subtree failed!") + return err + } + } + + subIntf = ifInfo.Subinterfaces.Subinterface[subintfid] + ygot.BuildEmptyTree(subIntf) + ygot.BuildEmptyTree(subIntf.Ipv4) + ygot.BuildEmptyTree(subIntf.Ipv6) + + for ipKey, _ := range intfIpMap { + log.Info("IP address = ", ipKey) + ipB, ipNetB, _ := parseCIDR(ipKey) + v4Flag := false + v6Flag := false + + var v4Address *ocbinds.OpenconfigInterfaces_Interfaces_Interface_Subinterfaces_Subinterface_Ipv4_Addresses_Address + var v6Address *ocbinds.OpenconfigInterfaces_Interfaces_Interface_Subinterfaces_Subinterface_Ipv6_Addresses_Address + if validIPv4(ipB.String()) { + if _, ok := subIntf.Ipv4.Addresses.Address[ipB.String()]; !ok { + _, err = subIntf.Ipv4.Addresses.NewAddress(ipB.String()) + } + v4Address = subIntf.Ipv4.Addresses.Address[ipB.String()] + v4Flag = true + } else if validIPv6(ipB.String()) { + if _, ok := subIntf.Ipv6.Addresses.Address[ipB.String()]; !ok { + _, err = subIntf.Ipv6.Addresses.NewAddress(ipB.String()) + } + v6Address = subIntf.Ipv6.Addresses.Address[ipB.String()] + v6Flag = true + } else { + log.Error("Invalid IP address " + ipB.String()) + continue + } + if err != nil { + log.Error("Creation of address subtree failed!") + return err + } + if v4Flag { + ygot.BuildEmptyTree(v4Address) + ipStr := new(string) + *ipStr = ipB.String() + v4Address.Ip = ipStr + prfxLen := new(uint8) + *prfxLen = ipNetB.Bits() + ipv4Str := new(string) + *ipv4Str = "ipv4" + if isState { + v4Address.State.Ip = ipStr + v4Address.State.PrefixLength = prfxLen + v4Address.State.Family = ipv4Str + } else { + v4Address.Config.Ip = ipStr + v4Address.Config.PrefixLength = prfxLen + } + } + if v6Flag { + ygot.BuildEmptyTree(v6Address) + ipStr := new(string) + *ipStr = ipB.String() + v6Address.Ip = ipStr + prfxLen := new(uint8) + *prfxLen = ipNetB.Bits() + ipv6Str := new(string) + *ipv6Str = "ipv6" + if isState { + v6Address.State.Ip = ipStr + v6Address.State.PrefixLength = prfxLen + v6Address.State.Family = ipv6Str + } else { + v6Address.Config.Ip = ipStr + v6Address.Config.PrefixLength = prfxLen + } + } + } + return err +} + +var DbToYang_intf_ip_addr_xfmr SubTreeXfmrDbToYang = func(inParams XfmrParams) error { + var err error + intfsObj := getIntfsRoot(inParams.ygRoot) + pathInfo := NewPathInfo(inParams.uri) + uriIfName := pathInfo.Var("name") + ifName := uriIfName + + targetUriPath := pathInfo.YangPath + log.Infof("DbToYang_intf_ip_addr_xfmr: uri:%v path:%v", inParams.uri, targetUriPath) + + reqPathInfo := NewPathInfo(inParams.requestUri) + requestUriPath := reqPathInfo.YangPath + var reqUriIfName string = reqPathInfo.Var("name") + + if (inParams.oper == GET) && + ((requestUriPath == "/openconfig-interfaces:interfaces" || requestUriPath == "/openconfig-interfaces:interfaces/interface") && reqUriIfName == "") { + _, present := inParams.txCache.Load("interface_subinterface_ip_read_once") + if present { + log.Info("DbToYang_intf_ip_addr_xfmr, top level GET, interface_subinterface_ip_read_once already cached") + return nil + } + + intfTypeList := [5]E_InterfaceType{IntfTypeEthernet, IntfTypeMgmt, IntfTypePortChannel, IntfTypeLoopback, IntfTypeSubIntf} + + // Get IP from all configDb table interfaces + for i := 0; i < len(intfTypeList); i++ { + intfTbl := IntfTypeTblMap[intfTypeList[i]] + + handleAllIntfIPGetForTable(inParams, intfTbl.cfgDb.intfTN, false) + } + + // Get IP from applDb INTF_TABLE interfaces except vlan intf + handleAllIntfIPGetForTable(inParams, "INTF_TABLE", true) + + inParams.txCache.Store("interface_subinterface_ip_read_once", true) + return nil + } else { + // Handle GET requests for given interface + var intfObj *ocbinds.OpenconfigInterfaces_Interfaces_Interface + ifName = *(&uriIfName) + + intfType, _, _ := getIntfTypeByName(ifName) + if IntfTypeVlan == intfType { + return nil + } + + if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces") { + if intfsObj != nil && intfsObj.Interface != nil && len(intfsObj.Interface) > 0 { + var ok bool = false + if intfObj, ok = intfsObj.Interface[uriIfName]; !ok { + intfObj, _ = intfsObj.NewInterface(uriIfName) + } + ygot.BuildEmptyTree(intfObj) + if intfObj.Subinterfaces == nil { + ygot.BuildEmptyTree(intfObj.Subinterfaces) + } + } else { + ygot.BuildEmptyTree(intfsObj) + intfObj, _ = intfsObj.NewInterface(uriIfName) + ygot.BuildEmptyTree(intfObj) + } + + err = handleIntfIPGetByTargetURI(inParams, targetUriPath, ifName, intfObj) + if err != nil { + return err + } + + } else { + err = errors.New("Invalid URI : " + targetUriPath) + } + } + + return err +} + +var YangToDb_intf_ip_addr_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) (map[string]map[string]db.Value, error) { + var err, oerr error + subOpMap := make(map[db.DBNum]map[string]map[string]db.Value) + subIntfmap := make(map[string]map[string]db.Value) + subIntfmap_del := make(map[string]map[string]db.Value) + var value db.Value + var overlapIP string + + pathInfo := NewPathInfo(inParams.uri) + uriIfName := pathInfo.Var("name") + idx := pathInfo.Var("index") + i64, err := strconv.ParseUint(idx, 10, 32) + i32 := uint32(i64) + ifName := uriIfName + + sonicIfName := &uriIfName + + log.Infof("YangToDb_intf_ip_addr_xfmr: Interface name retrieved from alias : %s is %s", ifName, *sonicIfName) + ifName = *sonicIfName + intfType, _, ierr := getIntfTypeByName(ifName) + if i32 > 0 { + intfType = IntfTypeSubIntf + ifName = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&ifName, &idx) + } + + if IntfTypeVxlan == intfType || IntfTypeVlan == intfType { + return subIntfmap, nil + } + + intfsObj := getIntfsRoot(inParams.ygRoot) + if intfsObj == nil || len(intfsObj.Interface) < 1 { + log.Info("YangToDb_intf_subintf_ip_xfmr : IntfsObj/interface list is empty.") + return subIntfmap, errors.New("IntfsObj/Interface is not specified") + } + + if ifName == "" { + errStr := "Interface KEY not present" + log.Info("YangToDb_intf_subintf_ip_xfmr : " + errStr) + return subIntfmap, errors.New(errStr) + } + + if intfType == IntfTypeUnset || ierr != nil { + errStr := "Invalid interface type IntfTypeUnset" + log.Info("YangToDb_intf_subintf_ip_xfmr : " + errStr) + return subIntfmap, errors.New(errStr) + } + /* Set invokeCRUSubtreeOnce flag to invoke subtree once */ + if inParams.invokeCRUSubtreeOnce != nil { + *inParams.invokeCRUSubtreeOnce = true + } + + /* Validate if DHCP_Relay is provisioned on the interface */ + prefixType := "" + if strings.Contains(inParams.uri, "ipv4") { + prefixType = "ipv4" + } else if strings.Contains(inParams.uri, "ipv6") { + prefixType = "ipv6" + } + + if inParams.oper == DELETE { + dhcpProv, _ := ValidateIntfProvisionedForRelay(inParams.d, ifName, prefixType, nil) + if dhcpProv { + errStr := "IP address cannot be deleted. DHCP Relay is configured on the interface." + return subIntfmap, tlerr.InvalidArgsError{Format: errStr} + } + } + + if _, ok := intfsObj.Interface[uriIfName]; !ok { + errStr := "Interface entry not found in Ygot tree, ifname: " + ifName + log.Info("YangToDb_intf_subintf_ip_xfmr : " + errStr) + return subIntfmap, errors.New(errStr) + } + + intTbl := IntfTypeTblMap[intfType] + tblName, _ := getIntfTableNameByDBId(intTbl, inParams.curDb) + intfObj := intfsObj.Interface[uriIfName] + + if intfObj.Subinterfaces == nil || len(intfObj.Subinterfaces.Subinterface) < 1 { + // Handling the scenario for Interface instance delete at interfaces/interface[name] level or subinterfaces container level + if inParams.oper == DELETE { + log.Info("Top level Interface instance delete or subinterfaces container delete for Interface: ", ifName) + return intf_ip_addr_del(inParams.d, ifName, tblName, nil) + } + errStr := "SubInterface node doesn't exist" + log.Info("YangToDb_intf_subintf_ip_xfmr : " + errStr) + err = tlerr.InvalidArgsError{Format: errStr} + return subIntfmap, err + } + if _, ok := intfObj.Subinterfaces.Subinterface[i32]; !ok { + log.Info("YangToDb_intf_subintf_ip_xfmr : No IP address handling required") + errStr := "SubInterface index 0 doesn't exist" + err = tlerr.InvalidArgsError{Format: errStr} + return subIntfmap, err + } + + subIntfObj := intfObj.Subinterfaces.Subinterface[i32] + if inParams.oper == DELETE { + return intf_ip_addr_del(inParams.d, ifName, tblName, subIntfObj) + } + + entry, dbErr := inParams.d.GetEntry(&db.TableSpec{Name: intTbl.cfgDb.intfTN}, db.Key{Comp: []string{ifName}}) + if dbErr != nil || !entry.IsPopulated() { + ifdb := make(map[string]string) + ifdb["NULL"] = "NULL" + value := db.Value{Field: ifdb} + if _, ok := subIntfmap[tblName]; !ok { + subIntfmap[tblName] = make(map[string]db.Value) + } + subIntfmap[tblName][ifName] = value + + } + if subIntfObj.Ipv4 != nil && subIntfObj.Ipv4.Addresses != nil { + for ip := range subIntfObj.Ipv4.Addresses.Address { + addr := subIntfObj.Ipv4.Addresses.Address[ip] + if addr.Config != nil { + if addr.Config.Ip == nil { + addr.Config.Ip = new(string) + *addr.Config.Ip = ip + } + log.Info("Ip:=", *addr.Config.Ip) + if addr.Config.PrefixLength == nil { + log.Error("Prefix Length empty!") + errStr := "Prefix Length not present" + err = tlerr.InvalidArgsError{Format: errStr} + return subIntfmap, err + } + log.Info("prefix:=", *addr.Config.PrefixLength) + if addr.Config.Family == nil { + addr.Config.Family = new(string) + *addr.Config.Family = "ipv4" + + } else if *addr.Config.Family == "ipv6" { + log.Error("Incorrect family ipv6!") + errStr := "IPv4 Family not present" + err = tlerr.InvalidArgsError{Format: errStr} + return subIntfmap, err + } + log.Info("family:=", *addr.Config.Family) + + ipPref := *addr.Config.Ip + "/" + strconv.Itoa(int(*addr.Config.PrefixLength)) + /* Check for IP overlap */ + overlapIP, oerr = validateIpOverlap(inParams.d, ifName, ipPref, tblName, true) + + ipEntry, _ := inParams.d.GetEntry(&db.TableSpec{Name: intTbl.cfgDb.intfTN}, db.Key{Comp: []string{ifName, ipPref}}) + ipMap, _ := getIntfIpByName(inParams.d, intTbl.cfgDb.intfTN, ifName, true, false, "") + + m := make(map[string]string) + alrdyCfgredIP, primaryIpAlrdyCfgred, err := utlValidateIpTypeForCfgredDiffIp(m, ipMap, &ipEntry, &ipPref, &ifName) + if err != nil { + return nil, err + } + // Primary IP config already happened and replacing it with new one + if primaryIpAlrdyCfgred && len(alrdyCfgredIP) != 0 && alrdyCfgredIP != ipPref { + subIntfmap_del[tblName] = make(map[string]db.Value) + key := ifName + "|" + alrdyCfgredIP + subIntfmap_del[tblName][key] = value + subOpMap[db.ConfigDB] = subIntfmap_del + log.Info("subOpMap: ", subOpMap) + inParams.subOpDataMap[DELETE] = &subOpMap + } + + intf_key := intf_intf_tbl_key_gen(ifName, *addr.Config.Ip, int(*addr.Config.PrefixLength), "|") + + value := db.Value{Field: m} + if _, ok := subIntfmap[tblName]; !ok { + subIntfmap[tblName] = make(map[string]db.Value) + } + subIntfmap[tblName][intf_key] = value + if log.V(3) { + log.Info("tblName :", tblName, " intf_key: ", intf_key, " data : ", value) + } + } + } + } + if subIntfObj.Ipv6 != nil && subIntfObj.Ipv6.Addresses != nil { + for ip := range subIntfObj.Ipv6.Addresses.Address { + addr := subIntfObj.Ipv6.Addresses.Address[ip] + if addr.Config != nil { + if addr.Config.Ip == nil { + addr.Config.Ip = new(string) + *addr.Config.Ip = ip + } + log.Info("Ipv6 IP:=", *addr.Config.Ip) + if addr.Config.PrefixLength == nil { + log.Error("Prefix Length empty!") + errStr := "Prefix Length not present" + err = tlerr.InvalidArgsError{Format: errStr} + return subIntfmap, err + } + log.Info("Ipv6 prefix:=", *addr.Config.PrefixLength) + if addr.Config.Family == nil { + addr.Config.Family = new(string) + *addr.Config.Family = "ipv6" + + } else if *addr.Config.Family == "ipv4" { + log.Error("Incorrect family!") + errStr := "IPv6 Family not present" + err = tlerr.InvalidArgsError{Format: errStr} + return subIntfmap, err + } + log.Info("family:=", *addr.Config.Family) + + /* Check for IPv6 overlap */ + ipPref := *addr.Config.Ip + "/" + strconv.Itoa(int(*addr.Config.PrefixLength)) + overlapIP, oerr = validateIpOverlap(inParams.d, ifName, ipPref, tblName, true) + + m := make(map[string]string) + + intf_key := intf_intf_tbl_key_gen(ifName, *addr.Config.Ip, int(*addr.Config.PrefixLength), "|") + + value := db.Value{Field: m} + if _, ok := subIntfmap[tblName]; !ok { + subIntfmap[tblName] = make(map[string]db.Value) + } + subIntfmap[tblName][intf_key] = value + log.Info("tblName :", tblName, "intf_key: ", intf_key, "data : ", value) + } + } + } + + if oerr != nil { + if overlapIP == "" { + log.Error(oerr) + return nil, tlerr.InvalidArgsError{Format: oerr.Error()} + } else { + subIntfmap_del[tblName] = make(map[string]db.Value) + key := ifName + "|" + overlapIP + subIntfmap_del[tblName][key] = value + subOpMap[db.ConfigDB] = subIntfmap_del + log.Info("subOpMap: ", subOpMap) + inParams.subOpDataMap[DELETE] = &subOpMap + } + } + + log.Info("YangToDb_intf_subintf_ip_xfmr : subIntfmap : ", subIntfmap) + return subIntfmap, err +} + +/* Check for IP overlap */ +func validateIpOverlap(d *db.DB, intf string, ipPref string, tblName string, isIntfIp bool) (string, error) { + log.Info("Checking for IP overlap ....") + + ipA, ipNetA, err := parseCIDR(ipPref) + if err != nil { + log.Info("Failed to parse IP address: ", ipPref) + return "", err + } + + var allIntfKeys []db.Key + + for key := range IntfTypeTblMap { + intTbl := IntfTypeTblMap[key] + keys, err := d.GetKeys(&db.TableSpec{Name: intTbl.cfgDb.intfTN}) + if err != nil { + log.Info("Failed to get keys; err=%v", err) + return "", err + } + allIntfKeys = append(allIntfKeys, keys...) + } + + if len(allIntfKeys) > 0 { + for _, key := range allIntfKeys { + if len(key.Comp) < 2 { + continue + } + ipB, ipNetB, perr := parseCIDR(key.Get(1)) + //Check if key has IP, if not continue + if perr != nil { + continue + } + if ipNetA.Contains(ipB) || ipNetB.Contains(ipA) { + if log.V(3) { + log.Info("IP: ", ipPref, " overlaps with ", key.Get(1), " of ", key.Get(0)) + } + + errStr := "IP " + ipPref + " overlaps with IP or IP Anycast " + key.Get(1) + " of Interface " + key.Get(0) + return "", errors.New(errStr) + } + } + } + return "", nil +} + +func utlCheckAndRetrievePrimaryIPConfigured(ipMap map[string]db.Value) (bool, string) { + for ipKey, _ := range ipMap { + return true, ipKey + } + return false, "" +} + +func utlValidateIpTypeForCfgredDiffIp(m map[string]string, ipMap map[string]db.Value, ipEntry *db.Value, ipPref *string, ifName *string) (string, bool, error) { + + dbgStr := "IPv4 address" + checkPrimIPCfgred, cfgredPrimIP := utlCheckAndRetrievePrimaryIPConfigured(ipMap) + if checkPrimIPCfgred && !ipEntry.IsPopulated() { + infoStr := "Primary " + dbgStr + " is already configured for interface: " + *ifName + log.Info(infoStr) + return cfgredPrimIP, true, nil + } + + return "", false, nil +} + +func intf_intf_tbl_key_gen(intfName string, ip string, prefixLen int, keySep string) string { + return intfName + keySep + ip + "/" + strconv.Itoa(prefixLen) +} +func parseCIDR(ipPref string) (netaddr.IP, netaddr.IPPrefix, error) { + prefIdx := strings.LastIndexByte(ipPref, '/') + if prefIdx <= 0 { + return netaddr.IP{}, netaddr.IPPrefix{}, fmt.Errorf("Invalid Prefix(%q): no'/'", ipPref) + } + prefLen, _ := strconv.Atoi(ipPref[prefIdx+1:]) + ipA, err := netaddr.ParseIP(ipPref[:prefIdx]) + if err != nil { + log.Infof("parseCIDR: Failed to parse IP address:%s : err : %s ", ipPref, err) + return netaddr.IP{}, netaddr.IPPrefix{}, fmt.Errorf("Failed to parse IP address: %s", ipPref) + } + + ipNetA, _ := ipA.Prefix(uint8(prefLen)) + return ipA, ipNetA, nil +} +func getIntfIpByName(dbCl *db.DB, tblName string, ifName string, ipv4 bool, ipv6 bool, ip string) (map[string]db.Value, error) { + var err error + intfIpMap := make(map[string]db.Value) + all := true + if !ipv4 || !ipv6 { + all = false + } + log.V(3).Info("Updating Interface IP Info from DB to Internal DS for Interface Name : ", ifName) + + keys, err := doGetIntfIpKeys(dbCl, tblName, ifName) + if log.V(3) { + log.Infof("Found %d keys for (%v)(%v)", len(keys), tblName, ifName) + } + if err != nil { + return intfIpMap, err + } + for _, key := range keys { + if len(key.Comp) < 2 { + continue + } + if key.Get(0) != ifName { + continue + } + if len(key.Comp) > 2 { + for i := range key.Comp { + if i == 0 || i == 1 { + continue + } + key.Comp[1] = key.Comp[1] + ":" + key.Comp[i] + } + } + if !all { + ipB, _, _ := parseCIDR(key.Get(1)) + if (validIPv4(ipB.String()) && (!ipv4)) || + (validIPv6(ipB.String()) && (!ipv6)) { + continue + } + if ip != "" { + if ipB.String() != ip { + continue + } + } + } + + ipInfo, _ := dbCl.GetEntry(&db.TableSpec{Name: tblName}, db.Key{Comp: []string{key.Get(0), key.Get(1)}}) + intfIpMap[key.Get(1)] = ipInfo + } + return intfIpMap, err +} + +/* Get all IP keys for given interface */ +func doGetIntfIpKeys(d *db.DB, tblName string, intfName string) ([]db.Key, error) { + var ipKeys []db.Key + var err error + + if intfName != "" { + ts := db.TableSpec{Name: tblName + d.Opts.KeySeparator + intfName} + ipKeys, err = d.GetKeys(&ts) + } else { + ipKeys, err = d.GetKeys(&db.TableSpec{Name: tblName}) + } + if log.V(3) { + log.Infof("doGetIntfIpKeys for intfName: %v tblName:%v ipKeys: %v", intfName, tblName, ipKeys) + } + return ipKeys, err +} +func validIPv4(ipAddress string) bool { + /* Dont allow ip addresses that start with "0." or "255."*/ + if strings.HasPrefix(ipAddress, "0.") || strings.HasPrefix(ipAddress, "255.") { + log.Info("validIP: IP is reserved ", ipAddress) + return false + } + + ip, err := netaddr.ParseIP(ipAddress) + if err != nil { + log.Infof("validIPv4: Failed to parse IP address %s : err : %s", ipAddress, err) + return false + } + + ipAddress = strings.Trim(ipAddress, " ") + + re, _ := regexp.Compile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`) + if re.MatchString(ipAddress) { + return validIP(ip) + } + return false +} + +func validIPv6(ipAddress string) bool { + ip, err := netaddr.ParseIP(ipAddress) + if err != nil { + log.Infof("validIPv6: Failed to parse IP address %s : err : %s", ipAddress, err) + return false + } + ipAddress = strings.Trim(ipAddress, " ") + + re, _ := regexp.Compile(`(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`) + if re.MatchString(ipAddress) { + return validIP(ip) + } + return false +} +func validIP(ip netaddr.IP) bool { + if ip.IsUnspecified() || ip.IsLoopback() || ip.IsMulticast() { + return false + } + return true +} + +func getIntfTableNameByDBId(intftbl IntfTblData, curDb db.DBNum) (string, error) { + + var tblName string + + switch curDb { + case db.ConfigDB: + tblName = intftbl.cfgDb.intfTN + case db.ApplDB: + tblName = intftbl.appDb.intfTN + case db.StateDB: + tblName = intftbl.stateDb.intfTN + default: + tblName = intftbl.cfgDb.intfTN + } + + return tblName, nil +} +func intf_ip_addr_del(d *db.DB, ifName string, tblName string, subIntf *ocbinds.OpenconfigInterfaces_Interfaces_Interface_Subinterfaces_Subinterface) (map[string]map[string]db.Value, error) { + var err error + subIntfmap := make(map[string]map[string]db.Value) + intfIpMap := make(map[string]db.Value) + + // Handles the case when the delete request at subinterfaces/subinterface[index = 0] + if subIntf == nil || (subIntf.Ipv4 == nil && subIntf.Ipv6 == nil) { + ipMap, _ := getIntfIpByName(d, tblName, ifName, true, true, "") + if len(ipMap) > 0 { + for k, v := range ipMap { + intfIpMap[k] = v + } + } + } + + // This handles the delete for a specific IPv4 address or a group of IPv4 addresses + if subIntf != nil && subIntf.Ipv4 != nil { + if subIntf.Ipv4.Addresses != nil { + if len(subIntf.Ipv4.Addresses.Address) < 1 { + ipMap, _ := getIntfIpByName(d, tblName, ifName, true, false, "") + if len(ipMap) > 0 { + for k, v := range ipMap { + intfIpMap[k] = v + } + } + } else { + for ip := range subIntf.Ipv4.Addresses.Address { + ipMap, _ := getIntfIpByName(d, tblName, ifName, true, false, ip) + + if len(ipMap) > 0 { + for k, v := range ipMap { + // Primary IPv4 delete + ifIpMap, _ := getIntfIpByName(d, tblName, ifName, true, false, "") + + checkIPCfgred, _ := utlCheckAndRetrievePrimaryIPConfigured(ifIpMap) + + if checkIPCfgred { + intfIpMap[k] = v + } + } + } + } + } + } else { + // Case when delete request is at IPv4 container level + ipMap, _ := getIntfIpByName(d, tblName, ifName, true, false, "") + if len(ipMap) > 0 { + for k, v := range ipMap { + intfIpMap[k] = v + } + } + } + } + + // This handles the delete for a specific IPv6 address or a group of IPv6 addresses + if subIntf != nil && subIntf.Ipv6 != nil { + if subIntf.Ipv6.Addresses != nil { + if len(subIntf.Ipv6.Addresses.Address) < 1 { + ipMap, _ := getIntfIpByName(d, tblName, ifName, false, true, "") + if len(ipMap) > 0 { + for k, v := range ipMap { + intfIpMap[k] = v + } + } + } else { + for ip := range subIntf.Ipv6.Addresses.Address { + ipMap, _ := getIntfIpByName(d, tblName, ifName, false, true, ip) + + if len(ipMap) > 0 { + for k, v := range ipMap { + intfIpMap[k] = v + } + } + } + } + } else { + // Case when the delete request is at IPv6 container level + ipMap, _ := getIntfIpByName(d, tblName, ifName, false, true, "") + if len(ipMap) > 0 { + for k, v := range ipMap { + intfIpMap[k] = v + } + } + } + } + if len(intfIpMap) > 0 { + if _, ok := subIntfmap[tblName]; !ok { + subIntfmap[tblName] = make(map[string]db.Value) + } + var data db.Value + for k := range intfIpMap { + ifKey := ifName + "|" + k + subIntfmap[tblName][ifKey] = data + } + intfIpCnt := 0 + _ = interfaceIPcount(tblName, d, &ifName, &intfIpCnt) + /* Delete interface from interface table if no other interface attributes/ip */ + ipCntAfterDeletion := intfIpCnt - len(intfIpMap) + if check_if_delete_l3_intf_entry(d, tblName, ifName, ipCntAfterDeletion, nil) { + if _, ok := subIntfmap[tblName]; !ok { + subIntfmap[tblName] = make(map[string]db.Value) + } + subIntfmap[tblName][ifName] = data + } + } + log.Info("Delete IP address list ", subIntfmap, " ", err) + return subIntfmap, err +} +func interfaceIPcount(tblName string, d *db.DB, intfName *string, ipCnt *int) error { + ipKeys, _ := d.GetKeysPattern(&db.TableSpec{Name: tblName}, db.Key{Comp: []string{*intfName, "*"}}) + *ipCnt = len(ipKeys) + return nil +} +func check_if_delete_l3_intf_entry(d *db.DB, tblName string, ifName string, ipCnt int, intfEntry *db.Value) bool { + if strings.HasPrefix(ifName, VLAN) { + sagIpKey, _ := d.GetKeysPattern(&db.TableSpec{Name: "SAG"}, db.Key{Comp: []string{ifName, "*"}}) + if len(sagIpKey) != 0 { + return false + } + } + if intfEntry == nil { + entry, err := d.GetEntry(&db.TableSpec{Name: tblName}, db.Key{Comp: []string{ifName}}) + if err != nil { + // Failed to read entry from config DB + return false + } + intfEntry = &entry + } + if ipCnt == 0 && intfEntry.IsPopulated() { + intfEntryMap := intfEntry.Field + _, nullValPresent := intfEntryMap["NULL"] + _, natZoneValPresent := intfEntryMap["nat_zone"] + /* Note: Unbinding shouldn't happen if VRF config is associated with interface. + Hence, we check for map length and only if either NULL or NAT value is present */ + if (len(intfEntryMap) == 1 && nullValPresent) || (len(intfEntryMap) == 2 && nullValPresent && natZoneValPresent) { + return true + } + } + return false +} + +var Subscribe_intf_ip_addr_xfmr = func(inParams XfmrSubscInParams) (XfmrSubscOutParams, error) { + if log.V(3) { + log.Info("Entering Subscribe_intf_ip_addr_xfmr") + } + var err error + var result XfmrSubscOutParams + + pathInfo := NewPathInfo(inParams.uri) + origTargetUriPath := pathInfo.YangPath + + log.Infof("Subscribe_intf_ip_addr_xfmr:- subscProc:%v URI: %s", inParams.subscProc, inParams.uri) + log.Infof("Subscribe_intf_ip_addr_xfmr:- Target URI path: %s", origTargetUriPath) + + // When the subscribe subtree is invoked in the GET or CRUD context the inParams.subscProc is set to TRANSLATE_EXISTS + if inParams.subscProc == TRANSLATE_EXISTS { + // Defer the DB resource check done by infra by setting the virtual table to true. + // Resource checks are now performed within the DbToYang or YangToDb subtree callback. + result.isVirtualTbl = true + return result, nil + } + if inParams.subscProc == TRANSLATE_SUBSCRIBE { + isRoutedVlan := false + + ifBasePath := "/openconfig-interfaces:interfaces/interface" + targetUriPath := origTargetUriPath[len(ifBasePath):] + + if strings.HasPrefix(targetUriPath, "/subinterfaces") { + targetUriPath = targetUriPath[len("/subinterfaces/subinterface"):] + } else { + isRoutedVlan = true + targetUriPath = targetUriPath[len("/openconfig-vlan:routed-vlan"):] + } + + if strings.HasPrefix(targetUriPath, "/openconfig-if-ip:ipv4") { + targetUriPath = targetUriPath[len("/openconfig-if-ip:ipv4/addresses"):] + } else { + targetUriPath = targetUriPath[len("/openconfig-if-ip:ipv6/addresses"):] + } + + if targetUriPath == "" || targetUriPath == "/address" { + result.isVirtualTbl = true + log.Info("Subscribe_intf_ip_addr_xfmr:- result.isVirtualTbl: ", result.isVirtualTbl) + return result, err + } + + result.onChange = OnchangeEnable + result.nOpts = ¬ificationOpts{} + result.nOpts.pType = OnChange + result.isVirtualTbl = false + + uriIfName := pathInfo.Var("name") + tableName := "" + ipKey := "" + ifKey := "" + subIfKey := "*" + + if uriIfName == "" || uriIfName == "*" { + ifKey = "*" + } else { + sonicIfName := &uriIfName + ifKey = *sonicIfName + } + + addressConfigPath := "/address/config" + addressStatePath := "/address/state" + + idx := pathInfo.Var("index") + if ifKey != "" { + if idx == "0" { + intfType, _, _ := getIntfTypeByName(ifKey) + intTbl := IntfTypeTblMap[intfType] + if targetUriPath == addressStatePath { + tableName = intTbl.appDb.intfTN + } else { + tableName = intTbl.cfgDb.intfTN + } + } else if idx == "*" || idx == "" { + subIfKey = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&ifKey, &idx) + } else { + tableName = "VLAN_SUB_INTERFACE" + ifKey = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&ifKey, &idx) + } + } + + ipKey = pathInfo.Var("ip") + if ipKey == "" { + ipKey = "*" + } + + if ipKey != "*" { + ipKey = ipKey + "/*" + } + + log.Infof("path:%v ifKey:%v, ipKey:%v tbl:[%v]", origTargetUriPath, ifKey, ipKey, tableName) + + keyName := "" + if targetUriPath == addressConfigPath { + keyName = ifKey + "|" + ipKey + if tableName != "" { + result.dbDataMap = RedisDbSubscribeMap{db.ConfigDB: {tableName: {keyName: {}}}} + } else { + if isRoutedVlan { + result.dbDataMap = RedisDbSubscribeMap{db.ConfigDB: {"VLAN_INTERFACE": {keyName: {}}}} + } else { + subIfKeyName := subIfKey + "|" + ipKey + result.dbDataMap = RedisDbSubscribeMap{db.ConfigDB: {"INTERFACE": {keyName: {}}, + "MGMT_INTERFACE": {keyName: {}}, + "LOOPBACK_INTERFACE": {keyName: {}}, + "VLAN_SUB_INTERFACE": {subIfKeyName: {}}, + "PORTCHANNEL_INTERFACE": {keyName: {}}}} + } + } + } else if targetUriPath == addressStatePath { + keyName = ifKey + ":" + ipKey + if tableName != "" { + result.dbDataMap = RedisDbSubscribeMap{db.ApplDB: {tableName: {keyName: {KEY_COMP_CNT: "2", DEL_AS_UPDATE: "true"}}}} + } else { + if isRoutedVlan { + result.dbDataMap = RedisDbSubscribeMap{db.ApplDB: {"INTF_TABLE": {keyName: {KEY_COMP_CNT: "2", DEL_AS_UPDATE: "true"}}}} + } else { + result.dbDataMap = RedisDbSubscribeMap{db.ApplDB: {"INTF_TABLE": {keyName: {KEY_COMP_CNT: "2", DEL_AS_UPDATE: "true"}}, + "MGMT_INTF_TABLE": {keyName: {KEY_COMP_CNT: "2", DEL_AS_UPDATE: "true"}}}} + } + } + } + + log.Info("Subscribe_intf_ip_addr_xfmr:- result dbDataMap: ", result.dbDataMap) + log.Info("Subscribe_intf_ip_addr_xfmr:- result secDbDataMap: ", result.secDbDataMap) + + return result, err + } + + result.isVirtualTbl = false + + result.dbDataMap = make(RedisDbSubscribeMap) + uriIfName := pathInfo.Var("name") + idx := pathInfo.Var("index") + sonicIfName := &uriIfName + keyName := *sonicIfName + + if keyName != "" { + intfType, _, _ := getIntfTypeByName(keyName) + intTbl := IntfTypeTblMap[intfType] + tblName := intTbl.cfgDb.intfTN + if idx != "" && idx != "0" { + tblName = "VLAN_SUB_INTERFACE" + keyName = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&keyName, &idx) + } + result.dbDataMap = RedisDbSubscribeMap{db.ConfigDB: {tblName: {keyName: {}}}} + } + log.Info("Returning Subscribe_intf_ip_addr_xfmr, result:", result) + result.needCache = true + result.nOpts = new(notificationOpts) + result.nOpts.mInterval = 15 + result.nOpts.pType = OnChange + log.Info("Returning Subscribe_intf_ip_addr_xfmr, result:", result) + return result, err + +} + +// YangToDb_subintf_ipv6_tbl_key_xfmr is a YangToDB Key transformer for IPv6 config. +var YangToDb_subintf_ipv6_tbl_key_xfmr KeyXfmrYangToDb = func(inParams XfmrParams) (string, error) { + if log.V(3) { + log.Info("Entering YangToDb_subintf_ipv6_tbl_key_xfmr") + } + + var err error + var inst_key string + pathInfo := NewPathInfo(inParams.uri) + ifName := pathInfo.Var("name") + + if log.V(3) { + log.Info("inParams.requestUri: ", inParams.requestUri) + } + idx := pathInfo.Var("index") + var i32 uint32 + i32 = 0 + if idx != "" { + i64, _ := strconv.ParseUint(idx, 10, 32) + i32 = uint32(i64) + } + inst_key = ifName + if i32 > 0 { + inst_key = ifName + "." + idx + } + log.Info("Exiting YangToDb_subintf_ipv6_tbl_key_xfmr, key ", inst_key) + return inst_key, err +} + +// DbToYang_subintf_ipv6_tbl_key_xfmr is a DbToYang key transformer for IPv6 config. +var DbToYang_subintf_ipv6_tbl_key_xfmr KeyXfmrDbToYang = func(inParams XfmrParams) (map[string]interface{}, error) { + if log.V(3) { + log.Info("Entering DbToYang_subintf_ipv6_tbl_key_xfmr") + } + + rmap := make(map[string]interface{}) + return rmap, nil +} + +// YangToDb_ipv6_enabled_xfmr is a YangToDB Field transformer for IPv6 config "enabled". +var YangToDb_ipv6_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[string]string, error) { + if log.V(3) { + log.Info("Entering YangToDb_ipv6_enabled_xfmr") + } + var err error + res_map := make(map[string]string) + pathInfo := NewPathInfo(inParams.uri) + ifUIName := pathInfo.Var("name") + idx := pathInfo.Var("index") + var i32 uint32 + i32 = 0 + if idx != "" { + i64, _ := strconv.ParseUint(idx, 10, 32) + i32 = uint32(i64) + } + + intfType, _, ierr := getIntfTypeByName(ifUIName) + if ierr != nil || intfType == IntfTypeUnset || intfType == IntfTypeVxlan || intfType == IntfTypeMgmt { + return res_map, errors.New("YangToDb_ipv6_enabled_xfmr, Error: Unsupported Interface: " + ifUIName) + } + + if ifUIName == "" { + errStr := "Interface KEY not present" + log.Info("YangToDb_ipv6_enabled_xfmr: " + errStr) + return res_map, errors.New(errStr) + } + + if inParams.param == nil { + return res_map, err + } + + // Vlan Interface (routed-vlan) contains only one Key "ifname" + // For all other interfaces (subinterfaces/subintfaces) will have 2 keys "ifname" & "subintf-index" + if len(pathInfo.Vars) < 2 && intfType != IntfTypeVlan { + return res_map, errors.New("YangToDb_ipv6_enabled_xfmr, Error: Invalid Key length") + } + + if log.V(3) { + log.Info("YangToDb_ipv6_enabled_xfmr, inParams.key: ", inParams.key) + } + + ifName := &ifUIName + + intTbl := IntfTypeTblMap[intfType] + tblName := intTbl.cfgDb.intfTN + if i32 > 0 { + tblName = "VLAN_SUB_INTERFACE" + ifName = utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(ifName, &idx) + } + ipMap, _ := getIntfIpByName(inParams.d, tblName, *ifName, true, true, "") + var enStr string + subOpMap := make(map[db.DBNum]map[string]map[string]db.Value) + subOpTblMap := make(map[string]map[string]db.Value) + field_map := make(map[string]db.Value) + res_values := db.Value{Field: map[string]string{}} + IntfMap := make(map[string]string) + + enabled, _ := inParams.param.(*bool) + if *enabled { + enStr = "enable" + } else { + enStr = "disable" + } + + IntfMapObj, err := inParams.d.GetEntry(&db.TableSpec{Name: tblName}, db.Key{Comp: []string{*ifName}}) + if err == nil || IntfMapObj.IsPopulated() { + IntfMap = IntfMapObj.Field + } + val, fieldExists := IntfMap["ipv6_use_link_local_only"] + if fieldExists && val == enStr { + // Check if already set to required value + log.Info("IPv6 is already %s.", enStr) + return nil, nil + } + + res_map["ipv6_use_link_local_only"] = enStr + if log.V(3) { + log.Info("YangToDb_ipv6_enabled_xfmr, res_map: ", res_map) + } + + if enStr == "disable" { + + if len(IntfMap) == 0 { + return nil, nil + } + + keys := make([]string, 0, len(IntfMap)) + for k := range IntfMap { + keys = append(keys, k) + } + check_keys := []string{"NULL", "ipv6_use_link_local_only"} + sort.Strings(keys) + /* Delete interface from interface table if disabling IPv6 and no other interface attributes/ip + else remove ipv6_use_link_local_only field */ + if !((reflect.DeepEqual(keys, check_keys) || reflect.DeepEqual(keys, check_keys[1:])) && len(ipMap) == 0) { + //Checking if field entry exists + if !fieldExists { + //Nothing to delete + return nil, nil + } + log.Info("YangToDb_ipv6_enabled_xfmr, deleting ipv6_use_link_local_only field") + //Delete field entry + (&res_values).Set("ipv6_use_link_local_only", enStr) + } + field_map[*ifName] = res_values + subOpTblMap[tblName] = field_map + subOpMap[db.ConfigDB] = subOpTblMap + inParams.subOpDataMap[DELETE] = &subOpMap + if log.V(3) { + log.Info("YangToDb_ipv6_enabled_xfmr, subOpMap: ", subOpMap) + } + return nil, nil + } + + return res_map, nil +} + +// DbToYang_ipv6_enabled_xfmr is a DbToYang Field transformer for IPv6 config "enabled". */ +var DbToYang_ipv6_enabled_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { + if log.V(3) { + log.Info("Entering DbToYang_ipv6_enabled_xfmr") + } + res_map := make(map[string]interface{}) + + if log.V(3) { + log.Info("DbToYang_ipv6_enabled_xfmr, inParams.key ", inParams.key) + } + pathInfo := NewPathInfo(inParams.uri) + ifName := pathInfo.Var("name") + + ifUIName := &ifName + log.Info("Interface Name = ", *ifUIName) + + intfType, _, _ := getIntfTypeByName(inParams.key) + if intfType == IntfTypeVxlan || intfType == IntfTypeMgmt { + return res_map, nil + } + + intTbl := IntfTypeTblMap[intfType] + tblName, _ := getIntfTableNameByDBId(intTbl, inParams.curDb) + + data := (*inParams.dbDataMap)[inParams.curDb] + + res_map["enabled"] = false + ipv6_status, ok := data[tblName][inParams.key].Field["ipv6_use_link_local_only"] + + if ok && ipv6_status == "enable" { + res_map["enabled"] = true + } + return res_map, nil +} diff --git a/translib/utils/utils.go b/translib/utils/utils.go index eb57a92a1..d2aee1656 100644 --- a/translib/utils/utils.go +++ b/translib/utils/utils.go @@ -65,3 +65,9 @@ func RemoveElement(sl []string, str string) []string { } return sl } +func GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(parentIf *string, subId *string) *string { + uiName := *parentIf + "." + *subId + key := *(&uiName) + log.V(3).Infof("GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID %s + %s => %s", *parentIf, *subId, key) + return &key +} From 0bc8f73aa1ba2315c75eff2453d23dc78b3d024c Mon Sep 17 00:00:00 2001 From: Satoru-Shinohara Date: Wed, 7 Feb 2024 19:56:44 -0500 Subject: [PATCH 03/13] remove unneeded code for unsupported interface types --- translib/transformer/xfmr_intf.go | 121 +++--------------------------- 1 file changed, 12 insertions(+), 109 deletions(-) diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go index 6d9ffb037..ecf636785 100644 --- a/translib/transformer/xfmr_intf.go +++ b/translib/transformer/xfmr_intf.go @@ -563,9 +563,7 @@ var DbToYang_intf_admin_status_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams log.Info("DbToYang_intf_admin_status_xfmr - Invalid interface type IntfTypeUnset") return result, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeVxlan == intfType { - return result, nil - } + intTbl := IntfTypeTblMap[intfType] tblName, _ := getPortTableNameByDBId(intTbl, inParams.curDb) @@ -597,19 +595,12 @@ var DbToYang_intf_admin_status_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams var YangToDb_intf_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[string]string, error) { res_map := make(map[string]string) - var ifName string + intfsObj := getIntfsRoot(inParams.ygRoot) if intfsObj == nil || len(intfsObj.Interface) < 1 { return res_map, nil - } else { - for infK := range intfsObj.Interface { - ifName = infK - } - } - intfType, _, _ := getIntfTypeByName(ifName) - if IntfTypeVxlan == intfType { - return res_map, nil } + enabled, _ := inParams.param.(*bool) var enStr string if *enabled { @@ -633,9 +624,6 @@ var DbToYang_intf_enabled_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (ma log.Info("DbToYang_intf_enabled_xfmr - Invalid interface type IntfTypeUnset") return result, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeVxlan == intfType { - return result, nil - } intTbl := IntfTypeTblMap[intfType] @@ -676,15 +664,9 @@ var YangToDb_intf_mtu_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[st } } intfType, _, _ := getIntfTypeByName(ifName) - if IntfTypeVxlan == intfType { - return res_map, nil - } + if inParams.oper == DELETE { log.Infof("Updating the Interface: %s with default MTU", ifName) - if intfType == IntfTypeLoopback { - log.Infof("MTU not supported for Loopback Interface Type: %d", intfType) - return res_map, nil - } /* Note: For the mtu delete request, res_map with delete operation and subOp map with update operation (default MTU value) is filled. This is because, transformer default updates the result DS for delete oper with table and key. This needs to be fixed by transformer @@ -700,19 +682,6 @@ var YangToDb_intf_mtu_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[st intfTypeVal, _ := inParams.param.(*uint16) intTypeValStr := strconv.FormatUint(uint64(*intfTypeVal), 10) - if IntfTypePortChannel == intfType { - /* Apply the MTU to all the portchannel member ports */ - //updateMemberPortsMtu(&inParams, &ifName, &intTypeValStr) - } else if IntfTypeEthernet == intfType { - /* Do not allow MTU configuration on a portchannel member port */ - lagId, _ := retrievePortChannelAssociatedWithIntf(&inParams, &ifName) - if lagId != nil { - log.Infof("%s is member of %s", ifName, *lagId) - errStr := "Configuration not allowed when port is member of Portchannel." - return nil, tlerr.InvalidArgsError{Format: errStr} - } - } - res_map["mtu"] = intTypeValStr return res_map, nil } @@ -728,9 +697,6 @@ var DbToYang_intf_mtu_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[st log.Info("DbToYang_intf_mtu_xfmr - Invalid interface type IntfTypeUnset") return result, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeVxlan == intfType { - return result, nil - } intTbl := IntfTypeTblMap[intfType] @@ -757,10 +723,9 @@ var DbToYang_intf_mtu_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[st return result, err } -// YangToDb_intf_eth_port_config_xfmr handles port-speed, unreliable-los, auto-neg and aggregate-id config. +// YangToDb_intf_eth_port_config_xfmr handles port-speed, and auto-neg config. var YangToDb_intf_eth_port_config_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) (map[string]map[string]db.Value, error) { var err error - var lagStr string memMap := make(map[string]map[string]db.Value) pathInfo := NewPathInfo(inParams.uri) @@ -774,14 +739,11 @@ var YangToDb_intf_eth_port_config_xfmr SubTreeXfmrYangToDb = func(inParams XfmrP err = tlerr.InvalidArgsError{Format: errStr} return nil, err } - if IntfTypeVxlan == intfType || IntfTypeVlan == intfType { - return memMap, nil - } intfsObj := getIntfsRoot(inParams.ygRoot) intfObj := intfsObj.Interface[uriIfName] - // Need to differentiate between config container delete and any attribute other than aggregate-id delete + // Need to differentiate between config container delete and any other attribute delete if inParams.oper == DELETE { /* Handles 3 cases case 1: Deletion request at top-level container / list @@ -794,30 +756,6 @@ var YangToDb_intf_eth_port_config_xfmr SubTreeXfmrYangToDb = func(inParams XfmrP intfObj.Ethernet.Config == nil || //case 3 (intfObj.Ethernet.Config != nil && requestUriPath == "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config") { - - // Delete all the Vlans for Interface and member port removal from port-channel - lagId, err := retrievePortChannelAssociatedWithIntf(&inParams, &ifName) - if lagId != nil { - log.Infof("%s is member of %s", ifName, *lagId) - } - if err != nil { - errStr := "Retrieveing PortChannel associated with Interface: " + ifName + " failed!" - return nil, errors.New(errStr) - } - if lagId != nil { - lagStr = *lagId - intTbl := IntfTypeTblMap[IntfTypePortChannel] - tblName, _ := getMemTableNameByDBId(intTbl, inParams.curDb) - - m := make(map[string]string) - value := db.Value{Field: m} - m["NULL"] = "NULL" - intfKey := lagStr + "|" + ifName - if _, ok := memMap[tblName]; !ok { - memMap[tblName] = make(map[string]db.Value) - } - memMap[tblName][intfKey] = value - } return memMap, err } } @@ -833,9 +771,7 @@ var YangToDb_intf_eth_port_config_xfmr SubTreeXfmrYangToDb = func(inParams XfmrP if ok { err = nil res_map[PORT_SPEED] = val - if IntfTypeMgmt != intfType { - res_map[PORT_AUTONEG] = "off" - } + res_map[PORT_AUTONEG] = "off" } else { err = tlerr.InvalidArgs("Invalid speed %s", val) } @@ -861,22 +797,14 @@ var YangToDb_intf_eth_port_config_xfmr SubTreeXfmrYangToDb = func(inParams XfmrP /* Handle AutoNegotiate config */ if intfObj.Ethernet.Config.AutoNegotiate != nil { - if intfType == IntfTypeMgmt || intfType == IntfTypeEthernet { + if intfType == IntfTypeEthernet { intTbl := IntfTypeTblMap[intfType] autoNeg := intfObj.Ethernet.Config.AutoNegotiate var enStr string if *autoNeg { - if IntfTypeMgmt == intfType { - enStr = "true" - } else { - enStr = "on" - } + enStr = "on" } else { - if IntfTypeMgmt == intfType { - enStr = "false" - } else { - enStr = "off" - } + enStr = "off" } res_map[PORT_AUTONEG] = enStr @@ -906,9 +834,6 @@ var DbToYang_intf_eth_port_config_xfmr SubTreeXfmrDbToYang = func(inParams XfmrP err = tlerr.InvalidArgsError{Format: errStr} return err } - if IntfTypeVxlan == intfType { - return nil - } intTbl := IntfTypeTblMap[intfType] tblName := intTbl.cfgDb.portTN entry, dbErr := inParams.dbs[db.ConfigDB].GetEntry(&db.TableSpec{Name: tblName}, db.Key{Comp: []string{ifName}}) @@ -939,19 +864,6 @@ var DbToYang_intf_eth_port_config_xfmr SubTreeXfmrDbToYang = func(inParams XfmrP get_cfg_obj = true } var errStr string - if get_cfg_obj { - is_id_populated := false - - if !is_id_populated { - errStr = "aggregate-id not set" - } - - // subscribe for aggregate-id needs "Resource not found" for delete notification - if (targetUriPath == "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config/openconfig-if-aggregate:aggregate-id") && (!is_id_populated) { - err = tlerr.NotFoundError{Format: "Resource not found"} - return err - } - } if entry.IsPopulated() { if get_cfg_obj || targetUriPath == "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/config/auto-negotiate" { @@ -994,19 +906,13 @@ var DbToYangPath_intf_eth_port_config_path_xfmr PathXfmrDbToYangFunc = func(para log.Info("DbToYangPath_intf_eth_port_config_path_xfmr: params: ", params) intfRoot := "/openconfig-interfaces:interfaces/interface" - - if (params.tblName != "PORT") && (params.tblName != "PORTCHANNEL_MEMBER") && - (params.tblName != "MGMT_PORT") { + if params.tblName != "PORT" { log.Info("DbToYangPath_intf_eth_port_config_path_xfmr: from wrong table: ", params.tblName) return nil } if (params.tblName == "PORT") && (len(params.tblKeyComp) > 0) { params.ygPathKeys[intfRoot+"/name"] = params.tblKeyComp[0] - } else if (params.tblName == "PORTCHANNEL_MEMBER") && (len(params.tblKeyComp) > 1) { - params.ygPathKeys[intfRoot+"/name"] = params.tblKeyComp[1] - } else if (params.tblName == "MGMT_PORT") && (len(params.tblKeyComp) > 0) { - params.ygPathKeys[intfRoot+"/name"] = params.tblKeyComp[0] } else { log.Info("DbToYangPath_intf_eth_port_config_path_xfmr, wrong param: tbl ", params.tblName, " key ", params.tblKeyComp) return nil @@ -1027,7 +933,7 @@ var DbToYang_intf_eth_auto_neg_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams log.Info("DbToYang_intf_eth_auto_neg_xfmr - Invalid interface type IntfTypeUnset") return result, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeMgmt != intfType && IntfTypeEthernet != intfType { + if IntfTypeEthernet != intfType { return result, nil } intTbl := IntfTypeTblMap[intfType] @@ -1058,9 +964,6 @@ var DbToYang_intf_eth_port_speed_xfmr FieldXfmrDbtoYang = func(inParams XfmrPara log.Info("DbToYang_intf_eth_port_speed_xfmr - Invalid interface type IntfTypeUnset") return result, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeVxlan == intfType || IntfTypeVlan == intfType { - return result, nil - } intTbl := IntfTypeTblMap[intfType] From 8ff5872a5e81024c22b15f19e3d5ab94a3a100a0 Mon Sep 17 00:00:00 2001 From: Satoru-Shinohara Date: Thu, 8 Feb 2024 15:33:14 -0500 Subject: [PATCH 04/13] remove functions that are no longet necessary --- translib/transformer/xfmr_intf.go | 49 ------------------------------- 1 file changed, 49 deletions(-) diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go index ecf636785..b93d5c2e3 100644 --- a/translib/transformer/xfmr_intf.go +++ b/translib/transformer/xfmr_intf.go @@ -302,55 +302,6 @@ func validateIntfExists(d *db.DB, intfTs string, ifName string) error { return nil } -func getMemTableNameByDBId(intftbl IntfTblData, curDb db.DBNum) (string, error) { - - var tblName string - - switch curDb { - case db.ConfigDB: - tblName = intftbl.cfgDb.memberTN - case db.ApplDB: - tblName = intftbl.appDb.memberTN - case db.StateDB: - tblName = intftbl.stateDb.memberTN - default: - tblName = intftbl.cfgDb.memberTN - } - - return tblName, nil -} - -func retrievePortChannelAssociatedWithIntf(inParams *XfmrParams, ifName *string) (*string, error) { - var err error - - if strings.HasPrefix(*ifName, ETHERNET) { - intTbl := IntfTypeTblMap[IntfTypePortChannel] - tblName, _ := getMemTableNameByDBId(intTbl, inParams.curDb) - var lagStr string - - lagKeys, err := inParams.d.GetKeysByPattern(&db.TableSpec{Name: tblName}, "*"+*ifName) - /* Find the port-channel the given ifname is part of */ - if err != nil { - return nil, err - } - var flag bool = false - for i := range lagKeys { - if *ifName == lagKeys[i].Get(1) { - flag = true - lagStr = lagKeys[i].Get(0) - log.Info("Given interface part of PortChannel: ", lagStr) - break - } - } - if !flag { - log.Info("Given Interface not part of any PortChannel") - return nil, err - } - return &lagStr, err - } - return nil, err -} - func updateDefaultMtu(inParams *XfmrParams, ifName *string, ifType E_InterfaceType, resMap map[string]string) error { var err error subOpMap := make(map[db.DBNum]map[string]map[string]db.Value) From 754c0d32485ad0fc51bf87f71d92a1434eeb905b Mon Sep 17 00:00:00 2001 From: Satoru-Shinohara Date: Sun, 11 Feb 2024 02:28:52 -0500 Subject: [PATCH 05/13] Code Clean-up - Remove unsupported interface related code --- translib/transformer/xfmr_intf.go | 136 +++++------------------------- 1 file changed, 21 insertions(+), 115 deletions(-) diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go index b93d5c2e3..7adf4e09e 100644 --- a/translib/transformer/xfmr_intf.go +++ b/translib/transformer/xfmr_intf.go @@ -78,23 +78,15 @@ func init() { const ( PORT_ADMIN_STATUS = "admin_status" - PORTCHANNEL_TN = "PORTCHANNEL" PORT_SPEED = "speed" PORT_AUTONEG = "autoneg" DEFAULT_MTU = "9100" ) const ( - PIPE = "|" - COLON = ":" - - ETHERNET = "Eth" - MGMT = "eth" - VLAN = "Vlan" - PORTCHANNEL = "PortChannel" - LOOPBACK = "Loopback" - VXLAN = "vtep" - MANAGEMENT = "Management" + PIPE = "|" + COLON = ":" + ETHERNET = "Eth" ) type TblData struct { @@ -116,24 +108,6 @@ var IntfTypeTblMap = map[E_InterfaceType]IntfTblData{ appDb: TblData{portTN: "PORT_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, stateDb: TblData{portTN: "PORT_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, }, - IntfTypeMgmt: IntfTblData{ - cfgDb: TblData{portTN: "MGMT_PORT", intfTN: "MGMT_INTERFACE", keySep: PIPE}, - appDb: TblData{portTN: "MGMT_PORT_TABLE", intfTN: "MGMT_INTF_TABLE", keySep: COLON}, - stateDb: TblData{portTN: "MGMT_PORT_TABLE", intfTN: "MGMT_INTERFACE_TABLE", keySep: PIPE}, - }, - IntfTypePortChannel: IntfTblData{ - cfgDb: TblData{portTN: "PORTCHANNEL", intfTN: "PORTCHANNEL_INTERFACE", memberTN: "PORTCHANNEL_MEMBER", keySep: PIPE}, - appDb: TblData{portTN: "LAG_TABLE", intfTN: "INTF_TABLE", keySep: COLON, memberTN: "LAG_MEMBER_TABLE"}, - stateDb: TblData{portTN: "LAG_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, - }, - IntfTypeVlan: IntfTblData{ - cfgDb: TblData{portTN: "VLAN", memberTN: "VLAN_MEMBER", intfTN: "VLAN_INTERFACE", keySep: PIPE}, - appDb: TblData{portTN: "VLAN_TABLE", memberTN: "VLAN_MEMBER_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, - }, - IntfTypeLoopback: IntfTblData{ - cfgDb: TblData{portTN: "LOOPBACK", intfTN: "LOOPBACK_INTERFACE", keySep: PIPE}, - appDb: TblData{portTN: "LOOPBACK_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, - }, IntfTypeSubIntf: IntfTblData{ cfgDb: TblData{portTN: "VLAN_SUB_INTERFACE", intfTN: "VLAN_SUB_INTERFACE", keySep: PIPE}, appDb: TblData{portTN: "PORT_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, @@ -142,9 +116,9 @@ var IntfTypeTblMap = map[E_InterfaceType]IntfTblData{ } var dbIdToTblMap = map[db.DBNum][]string{ - db.ConfigDB: {"PORT", "MGMT_PORT", "VLAN", "PORTCHANNEL", "LOOPBACK", "VXLAN_TUNNEL", "VLAN_SUB_INTERFACE"}, - db.ApplDB: {"PORT_TABLE", "MGMT_PORT_TABLE", "VLAN_TABLE", "LAG_TABLE"}, - db.StateDB: {"PORT_TABLE", "MGMT_PORT_TABLE", "LAG_TABLE"}, + db.ConfigDB: {"PORT", "VLAN_SUB_INTERFACE"}, + db.ApplDB: {"PORT_TABLE"}, + db.StateDB: {"PORT_TABLE"}, } var intfOCToSpeedMap = map[ocbinds.E_OpenconfigIfEthernet_ETHERNET_SPEED]string{ @@ -165,22 +139,15 @@ var intfOCToSpeedMap = map[ocbinds.E_OpenconfigIfEthernet_ETHERNET_SPEED]string{ type E_InterfaceType int64 const ( - IntfTypeUnset E_InterfaceType = 0 - IntfTypeEthernet E_InterfaceType = 1 - IntfTypeMgmt E_InterfaceType = 2 - IntfTypeVlan E_InterfaceType = 3 - IntfTypePortChannel E_InterfaceType = 4 - IntfTypeLoopback E_InterfaceType = 5 - IntfTypeVxlan E_InterfaceType = 6 - IntfTypeSubIntf E_InterfaceType = 7 + IntfTypeUnset E_InterfaceType = 0 + IntfTypeEthernet E_InterfaceType = 1 + IntfTypeSubIntf E_InterfaceType = 2 ) type E_InterfaceSubType int64 const ( - IntfSubTypeUnset E_InterfaceSubType = 0 - IntfSubTypeVlanL2 E_InterfaceSubType = 1 - InterfaceSubTypeVlanL3 E_InterfaceSubType = 2 + IntfSubTypeUnset E_InterfaceSubType = 0 ) func getIntfTypeByName(name string) (E_InterfaceType, E_InterfaceSubType, error) { @@ -268,16 +235,11 @@ func performIfNameKeyXfmrOp(inParams *XfmrParams, requestUriPath *string, ifName } if inParams.oper == REPLACE { if strings.Contains(*requestUriPath, "/openconfig-interfaces:interfaces/interface") { - if strings.Contains(*requestUriPath, "openconfig-if-ethernet:ethernet/openconfig-vlan:switched-vlan") || - strings.Contains(*requestUriPath, "mapped-vlans") { - log.Infof("allow replace operation for switched-vlan") - } else { - // OC interfaces yang does not have attributes to set Physical interface critical attributes like speed, alias, lanes, index. - // Replace/PUT request without the critical attributes would end up in deletion of the same in PORT table, which cannot be allowed. - // Hence block the Replace/PUT request for Physical interfaces alone. - err_str := "Replace/PUT request not allowed for Physical interfaces" - return tlerr.NotSupported(err_str) - } + // OC interfaces yang does not have attributes to set Physical interface critical attributes like speed. + // Replace/PUT request without the critical attributes would end up in deletion of the same in PORT table, which cannot be allowed. + // Hence block the Replace/PUT request for Physical interfaces alone. + err_str := "Replace/PUT request not allowed for Physical interfaces" + return tlerr.NotSupported(err_str) } } } @@ -375,33 +337,13 @@ var intf_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string, error) return tblList, tlerr.NotSupportedError{AppTag: "invalid-value", Path: "", Format: errStr} } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/config") { - if IntfTypeVxlan != intfType { - tblList = append(tblList, intTbl.cfgDb.portTN) - } + tblList = append(tblList, intTbl.cfgDb.portTN) - } else if intfType != IntfTypeEthernet && intfType != IntfTypeMgmt && + } else if intfType != IntfTypeEthernet && strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet") { //Checking interface type at container level, if not Ethernet type return nil return nil, nil - } else if intfType != IntfTypePortChannel && - strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-aggregate:aggregation") { - //Checking interface type at container level, if not PortChannel type return nil - return nil, nil - - } else if intfType != IntfTypeVlan && - strings.HasPrefix(targetUriPath, "openconfig-interfaces:interfaces/interface/openconfig-vlan:routed-vlan") { - //Checking interface type at container level, if not Vlan type return nil - return nil, nil - - } else if intfType != IntfTypeVxlan && - strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-vxlan:vxlan-if") { - //Checking interface type at container level, if not Vxlan type return nil - return nil, nil - - } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/state/counters") { - tblList = append(tblList, "NONE") - } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/state") || strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/ethernet/state") || strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet/state") { @@ -1041,16 +983,13 @@ var intf_subintfs_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string } if ifName == "*" { - _intfTypeList = append(_intfTypeList, IntfTypeEthernet, IntfTypeMgmt, IntfTypePortChannel, IntfTypeLoopback) + _intfTypeList = append(_intfTypeList, IntfTypeEthernet) _addSubIntfToList() } else { _ifType, _, _err := getIntfTypeByName(ifName) if _ifType == IntfTypeUnset || _err != nil { return tblList, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeVlan == _ifType || IntfTypeVxlan == _ifType { - return tblList, nil - } _intfTypeList = append(_intfTypeList, _ifType) _addSubIntfToList() } @@ -1135,10 +1074,6 @@ var YangToDb_intf_subintfs_xfmr KeyXfmrYangToDb = func(inParams XfmrParams) (str if intfType == IntfTypeUnset || ierr != nil { return ifName, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeVlan == intfType { - log.Info("YangToDb_intf_subintfs_xfmr - IntfTypeVlan") - return ifName, nil - } idx := pathInfo.Var("index") @@ -1413,12 +1348,7 @@ func ValidateIntfProvisionedForRelay(d *db.DB, ifName string, prefixIp string, e intTbl := IntfTypeTblMap[intfType] tblList = intTbl.cfgDb.intfTN - // for VLAN - DHCP info is stored in the VLAN Table - if intfType == IntfTypeVlan { - tblList = intTbl.cfgDb.portTN - } - - if entry == nil || intfType == IntfTypeVlan { + if entry == nil { ent, dbErr := d.GetEntry(&db.TableSpec{Name: tblList}, db.Key{Comp: []string{ifName}}) entry = &ent if dbErr != nil { @@ -1630,7 +1560,7 @@ var DbToYang_intf_ip_addr_xfmr SubTreeXfmrDbToYang = func(inParams XfmrParams) e return nil } - intfTypeList := [5]E_InterfaceType{IntfTypeEthernet, IntfTypeMgmt, IntfTypePortChannel, IntfTypeLoopback, IntfTypeSubIntf} + intfTypeList := [2]E_InterfaceType{IntfTypeEthernet, IntfTypeSubIntf} // Get IP from all configDb table interfaces for i := 0; i < len(intfTypeList); i++ { @@ -1649,11 +1579,6 @@ var DbToYang_intf_ip_addr_xfmr SubTreeXfmrDbToYang = func(inParams XfmrParams) e var intfObj *ocbinds.OpenconfigInterfaces_Interfaces_Interface ifName = *(&uriIfName) - intfType, _, _ := getIntfTypeByName(ifName) - if IntfTypeVlan == intfType { - return nil - } - if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces") { if intfsObj != nil && intfsObj.Interface != nil && len(intfsObj.Interface) > 0 { var ok bool = false @@ -1708,10 +1633,6 @@ var YangToDb_intf_ip_addr_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) ( ifName = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&ifName, &idx) } - if IntfTypeVxlan == intfType || IntfTypeVlan == intfType { - return subIntfmap, nil - } - intfsObj := getIntfsRoot(inParams.ygRoot) if intfsObj == nil || len(intfsObj.Interface) < 1 { log.Info("YangToDb_intf_subintf_ip_xfmr : IntfsObj/interface list is empty.") @@ -2244,12 +2165,6 @@ func interfaceIPcount(tblName string, d *db.DB, intfName *string, ipCnt *int) er return nil } func check_if_delete_l3_intf_entry(d *db.DB, tblName string, ifName string, ipCnt int, intfEntry *db.Value) bool { - if strings.HasPrefix(ifName, VLAN) { - sagIpKey, _ := d.GetKeysPattern(&db.TableSpec{Name: "SAG"}, db.Key{Comp: []string{ifName, "*"}}) - if len(sagIpKey) != 0 { - return false - } - } if intfEntry == nil { entry, err := d.GetEntry(&db.TableSpec{Name: tblName}, db.Key{Comp: []string{ifName}}) if err != nil { @@ -2488,7 +2403,7 @@ var YangToDb_ipv6_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (ma } intfType, _, ierr := getIntfTypeByName(ifUIName) - if ierr != nil || intfType == IntfTypeUnset || intfType == IntfTypeVxlan || intfType == IntfTypeMgmt { + if ierr != nil || intfType == IntfTypeUnset { return res_map, errors.New("YangToDb_ipv6_enabled_xfmr, Error: Unsupported Interface: " + ifUIName) } @@ -2502,12 +2417,6 @@ var YangToDb_ipv6_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (ma return res_map, err } - // Vlan Interface (routed-vlan) contains only one Key "ifname" - // For all other interfaces (subinterfaces/subintfaces) will have 2 keys "ifname" & "subintf-index" - if len(pathInfo.Vars) < 2 && intfType != IntfTypeVlan { - return res_map, errors.New("YangToDb_ipv6_enabled_xfmr, Error: Invalid Key length") - } - if log.V(3) { log.Info("YangToDb_ipv6_enabled_xfmr, inParams.key: ", inParams.key) } @@ -2604,9 +2513,6 @@ var DbToYang_ipv6_enabled_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (ma log.Info("Interface Name = ", *ifUIName) intfType, _, _ := getIntfTypeByName(inParams.key) - if intfType == IntfTypeVxlan || intfType == IntfTypeMgmt { - return res_map, nil - } intTbl := IntfTypeTblMap[intfType] tblName, _ := getIntfTableNameByDBId(intTbl, inParams.curDb) From e52935c2df678a61d12d425fb10af52b5b7585a6 Mon Sep 17 00:00:00 2001 From: Satoru-Shinohara Date: Tue, 13 Feb 2024 11:58:26 -0500 Subject: [PATCH 06/13] Add back needed code --- translib/transformer/xfmr_intf.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go index 7adf4e09e..cc25eb128 100644 --- a/translib/transformer/xfmr_intf.go +++ b/translib/transformer/xfmr_intf.go @@ -153,11 +153,6 @@ const ( func getIntfTypeByName(name string) (E_InterfaceType, E_InterfaceSubType, error) { var err error - if strings.Contains(name, ".") { - if strings.HasPrefix(name, ETHERNET) || strings.HasPrefix(name, "Po") { - return IntfTypeSubIntf, IntfSubTypeUnset, err - } - } if strings.HasPrefix(name, ETHERNET) { return IntfTypeEthernet, IntfSubTypeUnset, err } else { @@ -2417,6 +2412,12 @@ var YangToDb_ipv6_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (ma return res_map, err } + // Vlan Interface (routed-vlan) contains only one Key "ifname" + // For all other interfaces (subinterfaces/subintfaces) will have 2 keys "ifname" & "subintf-index" + if len(pathInfo.Vars) < 2 { + return res_map, errors.New("YangToDb_ipv6_enabled_xfmr, Error: Invalid Key length") + } + if log.V(3) { log.Info("YangToDb_ipv6_enabled_xfmr, inParams.key: ", inParams.key) } From 5d36584671db72d14222cc7c197fbd5a057efd5a Mon Sep 17 00:00:00 2001 From: Nikita Agarwal Date: Tue, 13 Feb 2024 11:43:41 -0800 Subject: [PATCH 07/13] Removing unnecessary code. --- .../openconfig-interfaces-deviation.yang | 4 + translib/transformer/xfmr_intf.go | 467 ++---------------- translib/utils/utils.go | 7 - 3 files changed, 41 insertions(+), 437 deletions(-) diff --git a/models/yang/extensions/openconfig-interfaces-deviation.yang b/models/yang/extensions/openconfig-interfaces-deviation.yang index e3fd326b7..7050b8706 100644 --- a/models/yang/extensions/openconfig-interfaces-deviation.yang +++ b/models/yang/extensions/openconfig-interfaces-deviation.yang @@ -132,4 +132,8 @@ module openconfig-interfaces-deviation { deviate not-supported; } + deviation /oc-intf:interfaces/oc-intf:interface/oc-vlan:routed-vlan { + deviate not-supported; + } + } diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go index 6d9ffb037..e4232b358 100644 --- a/translib/transformer/xfmr_intf.go +++ b/translib/transformer/xfmr_intf.go @@ -32,7 +32,6 @@ import ( "github.com/Azure/sonic-mgmt-common/translib/db" "github.com/Azure/sonic-mgmt-common/translib/ocbinds" "github.com/Azure/sonic-mgmt-common/translib/tlerr" - "github.com/Azure/sonic-mgmt-common/translib/utils" log "github.com/golang/glog" "github.com/openconfig/ygot/ygot" ) @@ -78,7 +77,6 @@ func init() { const ( PORT_ADMIN_STATUS = "admin_status" - PORTCHANNEL_TN = "PORTCHANNEL" PORT_SPEED = "speed" PORT_AUTONEG = "autoneg" DEFAULT_MTU = "9100" @@ -89,12 +87,6 @@ const ( COLON = ":" ETHERNET = "Eth" - MGMT = "eth" - VLAN = "Vlan" - PORTCHANNEL = "PortChannel" - LOOPBACK = "Loopback" - VXLAN = "vtep" - MANAGEMENT = "Management" ) type TblData struct { @@ -116,35 +108,12 @@ var IntfTypeTblMap = map[E_InterfaceType]IntfTblData{ appDb: TblData{portTN: "PORT_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, stateDb: TblData{portTN: "PORT_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, }, - IntfTypeMgmt: IntfTblData{ - cfgDb: TblData{portTN: "MGMT_PORT", intfTN: "MGMT_INTERFACE", keySep: PIPE}, - appDb: TblData{portTN: "MGMT_PORT_TABLE", intfTN: "MGMT_INTF_TABLE", keySep: COLON}, - stateDb: TblData{portTN: "MGMT_PORT_TABLE", intfTN: "MGMT_INTERFACE_TABLE", keySep: PIPE}, - }, - IntfTypePortChannel: IntfTblData{ - cfgDb: TblData{portTN: "PORTCHANNEL", intfTN: "PORTCHANNEL_INTERFACE", memberTN: "PORTCHANNEL_MEMBER", keySep: PIPE}, - appDb: TblData{portTN: "LAG_TABLE", intfTN: "INTF_TABLE", keySep: COLON, memberTN: "LAG_MEMBER_TABLE"}, - stateDb: TblData{portTN: "LAG_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, - }, - IntfTypeVlan: IntfTblData{ - cfgDb: TblData{portTN: "VLAN", memberTN: "VLAN_MEMBER", intfTN: "VLAN_INTERFACE", keySep: PIPE}, - appDb: TblData{portTN: "VLAN_TABLE", memberTN: "VLAN_MEMBER_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, - }, - IntfTypeLoopback: IntfTblData{ - cfgDb: TblData{portTN: "LOOPBACK", intfTN: "LOOPBACK_INTERFACE", keySep: PIPE}, - appDb: TblData{portTN: "LOOPBACK_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, - }, - IntfTypeSubIntf: IntfTblData{ - cfgDb: TblData{portTN: "VLAN_SUB_INTERFACE", intfTN: "VLAN_SUB_INTERFACE", keySep: PIPE}, - appDb: TblData{portTN: "PORT_TABLE", intfTN: "INTF_TABLE", keySep: COLON}, - stateDb: TblData{portTN: "PORT_TABLE", intfTN: "INTERFACE_TABLE", keySep: PIPE}, - }, } var dbIdToTblMap = map[db.DBNum][]string{ - db.ConfigDB: {"PORT", "MGMT_PORT", "VLAN", "PORTCHANNEL", "LOOPBACK", "VXLAN_TUNNEL", "VLAN_SUB_INTERFACE"}, - db.ApplDB: {"PORT_TABLE", "MGMT_PORT_TABLE", "VLAN_TABLE", "LAG_TABLE"}, - db.StateDB: {"PORT_TABLE", "MGMT_PORT_TABLE", "LAG_TABLE"}, + db.ConfigDB: {"PORT"}, + db.ApplDB: {"PORT_TABLE"}, + db.StateDB: {"PORT_TABLE"}, } var intfOCToSpeedMap = map[ocbinds.E_OpenconfigIfEthernet_ETHERNET_SPEED]string{ @@ -167,30 +136,17 @@ type E_InterfaceType int64 const ( IntfTypeUnset E_InterfaceType = 0 IntfTypeEthernet E_InterfaceType = 1 - IntfTypeMgmt E_InterfaceType = 2 - IntfTypeVlan E_InterfaceType = 3 - IntfTypePortChannel E_InterfaceType = 4 - IntfTypeLoopback E_InterfaceType = 5 - IntfTypeVxlan E_InterfaceType = 6 - IntfTypeSubIntf E_InterfaceType = 7 ) type E_InterfaceSubType int64 const ( - IntfSubTypeUnset E_InterfaceSubType = 0 - IntfSubTypeVlanL2 E_InterfaceSubType = 1 - InterfaceSubTypeVlanL3 E_InterfaceSubType = 2 + IntfSubTypeUnset E_InterfaceSubType = 0 ) func getIntfTypeByName(name string) (E_InterfaceType, E_InterfaceSubType, error) { var err error - if strings.Contains(name, ".") { - if strings.HasPrefix(name, ETHERNET) || strings.HasPrefix(name, "Po") { - return IntfTypeSubIntf, IntfSubTypeUnset, err - } - } if strings.HasPrefix(name, ETHERNET) { return IntfTypeEthernet, IntfSubTypeUnset, err } else { @@ -227,13 +183,6 @@ func getPortTableNameByDBId(intftbl IntfTblData, curDb db.DBNum) (string, error) func performIfNameKeyXfmrOp(inParams *XfmrParams, requestUriPath *string, ifName *string, ifType E_InterfaceType, subintfid uint32) error { var err error switch inParams.oper { - case GET: - if ifType == IntfTypeSubIntf && subintfid == 0 { - errStr := "Invalid interface name: " + *ifName - log.Infof("Invalid interface name: %s for GET path: %v", *ifName, *requestUriPath) - err = tlerr.InvalidArgsError{Format: errStr} - return err - } case DELETE: if *requestUriPath == "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface" && subintfid != 0 { return nil @@ -268,16 +217,11 @@ func performIfNameKeyXfmrOp(inParams *XfmrParams, requestUriPath *string, ifName } if inParams.oper == REPLACE { if strings.Contains(*requestUriPath, "/openconfig-interfaces:interfaces/interface") { - if strings.Contains(*requestUriPath, "openconfig-if-ethernet:ethernet/openconfig-vlan:switched-vlan") || - strings.Contains(*requestUriPath, "mapped-vlans") { - log.Infof("allow replace operation for switched-vlan") - } else { - // OC interfaces yang does not have attributes to set Physical interface critical attributes like speed, alias, lanes, index. - // Replace/PUT request without the critical attributes would end up in deletion of the same in PORT table, which cannot be allowed. - // Hence block the Replace/PUT request for Physical interfaces alone. - err_str := "Replace/PUT request not allowed for Physical interfaces" - return tlerr.NotSupported(err_str) - } + // OC interfaces yang does not have attributes to set Physical interface critical attributes like speed, alias, lanes, index. + // Replace/PUT request without the critical attributes would end up in deletion of the same in PORT table, which cannot be allowed. + // Hence block the Replace/PUT request for Physical interfaces alone. + err_str := "Replace/PUT request not allowed for Physical interfaces" + return tlerr.NotSupported(err_str) } } } @@ -400,13 +344,6 @@ var intf_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string, error) return dbIdToTblMap[inParams.curDb], nil } } - idx := pathInfo.Var("index") - var i32 uint32 - i32 = 0 - if idx != "" { - i64, _ := strconv.ParseUint(idx, 10, 32) - i32 = uint32(i64) - } intfType, _, ierr := getIntfTypeByName(ifName) if intfType == IntfTypeUnset || ierr != nil { @@ -424,32 +361,7 @@ var intf_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string, error) return tblList, tlerr.NotSupportedError{AppTag: "invalid-value", Path: "", Format: errStr} } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/config") { - if IntfTypeVxlan != intfType { - tblList = append(tblList, intTbl.cfgDb.portTN) - } - - } else if intfType != IntfTypeEthernet && intfType != IntfTypeMgmt && - strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-ethernet:ethernet") { - //Checking interface type at container level, if not Ethernet type return nil - return nil, nil - - } else if intfType != IntfTypePortChannel && - strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-if-aggregate:aggregation") { - //Checking interface type at container level, if not PortChannel type return nil - return nil, nil - - } else if intfType != IntfTypeVlan && - strings.HasPrefix(targetUriPath, "openconfig-interfaces:interfaces/interface/openconfig-vlan:routed-vlan") { - //Checking interface type at container level, if not Vlan type return nil - return nil, nil - - } else if intfType != IntfTypeVxlan && - strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/openconfig-vxlan:vxlan-if") { - //Checking interface type at container level, if not Vxlan type return nil - return nil, nil - - } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/state/counters") { - tblList = append(tblList, "NONE") + tblList = append(tblList, intTbl.cfgDb.portTN) } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/state") || strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/ethernet/state") || @@ -461,11 +373,7 @@ var intf_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string, error) strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/addresses/address/config") || strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv6/config") || strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/config") { - if i32 > 0 { - tblList = append(tblList, "VLAN_SUB_INTERFACE") - } else { - tblList = append(tblList, intTbl.cfgDb.intfTN) - } + tblList = append(tblList, intTbl.cfgDb.intfTN) } else if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/ipv4/addresses/address/state") || strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv4/addresses/address/state") || strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/openconfig-if-ip:ipv6/addresses/address/state") || @@ -563,9 +471,6 @@ var DbToYang_intf_admin_status_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams log.Info("DbToYang_intf_admin_status_xfmr - Invalid interface type IntfTypeUnset") return result, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeVxlan == intfType { - return result, nil - } intTbl := IntfTypeTblMap[intfType] tblName, _ := getPortTableNameByDBId(intTbl, inParams.curDb) @@ -597,18 +502,9 @@ var DbToYang_intf_admin_status_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams var YangToDb_intf_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (map[string]string, error) { res_map := make(map[string]string) - var ifName string intfsObj := getIntfsRoot(inParams.ygRoot) if intfsObj == nil || len(intfsObj.Interface) < 1 { return res_map, nil - } else { - for infK := range intfsObj.Interface { - ifName = infK - } - } - intfType, _, _ := getIntfTypeByName(ifName) - if IntfTypeVxlan == intfType { - return res_map, nil } enabled, _ := inParams.param.(*bool) var enStr string @@ -633,9 +529,6 @@ var DbToYang_intf_enabled_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (ma log.Info("DbToYang_intf_enabled_xfmr - Invalid interface type IntfTypeUnset") return result, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeVxlan == intfType { - return result, nil - } intTbl := IntfTypeTblMap[intfType] @@ -1147,93 +1040,18 @@ var intf_pre_xfmr PreXfmrFunc = func(inParams XfmrParams) error { return err } -func populateVlanSubIntfTblKeys(inParams XfmrParams) error { - var key string - - (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"] = make(map[string]db.Value) - mapIntfKeys, _ := inParams.d.GetKeys(&db.TableSpec{Name: "VLAN_SUB_INTERFACE"}) - if len(mapIntfKeys) > 0 { - for _, intfKey := range mapIntfKeys { - key = intfKey.Get(0) - key = *(&key) - if _, ok := (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"][key]; !ok { - (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"][key] = db.Value{Field: make(map[string]string)} - (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"][key].Field["NULL"] = "NULL" - } - } - } - - if log.V(3) { - log.Infof("populateVlanSubIntfTblKeys, configDB dbdataMap[\"VLAN_SUB_INTERFACE\"]: %v ", (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"]) - } - - return nil -} - var intf_subintfs_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string, error) { var tblList []string pathInfo := NewPathInfo(inParams.uri) - ifName := pathInfo.Var("name") idx := pathInfo.Var("index") - if inParams.oper == SUBSCRIBE { - var _intfTypeList []E_InterfaceType - - _addSubIntfToList := func() { - if idx == "*" || idx != "0" { - _intfTypeList = append(_intfTypeList, IntfTypeSubIntf) - } - } - - if ifName == "*" { - _intfTypeList = append(_intfTypeList, IntfTypeEthernet, IntfTypeMgmt, IntfTypePortChannel, IntfTypeLoopback) - _addSubIntfToList() - } else { - _ifType, _, _err := getIntfTypeByName(ifName) - if _ifType == IntfTypeUnset || _err != nil { - return tblList, errors.New("Invalid interface type IntfTypeUnset") - } - if IntfTypeVlan == _ifType || IntfTypeVxlan == _ifType { - return tblList, nil - } - _intfTypeList = append(_intfTypeList, _ifType) - _addSubIntfToList() - } - - for _, _ifType := range _intfTypeList { - _intfTblName, _ := getIntfTableNameByDBId(IntfTypeTblMap[_ifType], inParams.curDb) - tblList = append(tblList, _intfTblName) - } - - log.V(3).Info("intf_subintfs_table_xfmr: URI: ", inParams.uri, " OP:", inParams.oper, " ifName:", ifName, " idx:", idx, " tblList:", tblList) - return tblList, nil - } - - //if GET at top level, populate the VLAN_SUB_INTERFACE table with keys and store the flag to txCache - val, present := inParams.txCache.Load("vlan_sub_intf_tbl_keys_read") - reqPathInfo := NewPathInfo(inParams.requestUri) - requestUriPath := reqPathInfo.YangPath - var reqUriIfName string = reqPathInfo.Var("name") - if inParams.oper == GET && (requestUriPath == "/openconfig-interfaces:interfaces" || - requestUriPath == "/openconfig-interfaces:interfaces/interface") && reqUriIfName == "" { - if !present || val != true { - if inParams.dbDataMap != nil { - populateVlanSubIntfTblKeys(inParams) - inParams.txCache.Store("vlan_sub_intf_tbl_keys_read", true) - val = true - log.Info("intf_subintfs_table_xfmr, cached vlan_sub_intf_tbl_keys_read") - } - } - } - if idx == "" { if inParams.oper == GET || inParams.oper == DELETE { if inParams.dbDataMap != nil { (*inParams.dbDataMap)[db.ConfigDB]["SUBINTF_TBL"] = make(map[string]db.Value) (*inParams.dbDataMap)[db.ConfigDB]["SUBINTF_TBL"]["0"] = db.Value{Field: make(map[string]string)} tblList = append(tblList, "SUBINTF_TBL") - tblList = append(tblList, "VLAN_SUB_INTERFACE") } } log.Info("intf_subintfs_table_xfmr - Subinterface get operation ") @@ -1245,17 +1063,6 @@ var intf_subintfs_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string (*inParams.dbDataMap)[db.ConfigDB]["SUBINTF_TBL"]["0"].Field["NULL"] = "NULL" } tblList = append(tblList, "SUBINTF_TBL") - } else { - if inParams.dbDataMap != nil { - (*inParams.dbDataMap)[db.ConfigDB]["VLAN_SUB_INTERFACE"] = make(map[string]db.Value) - if val == true { - //reset cached flag - inParams.txCache.Store("vlan_sub_intf_tbl_keys_read", false) - log.Info("intf_subintfs_table_xfmr, reset vlan_sub_intf_tbl_keys_read cache") - } - } - tblList = append(tblList, "VLAN_SUB_INTERFACE") - *inParams.isVirtualTbl = false } if log.V(3) { log.Info("intf_subintfs_table_xfmr - Subinterface get operation ") @@ -1281,10 +1088,6 @@ var YangToDb_intf_subintfs_xfmr KeyXfmrYangToDb = func(inParams XfmrParams) (str if intfType == IntfTypeUnset || ierr != nil { return ifName, errors.New("Invalid interface type IntfTypeUnset") } - if IntfTypeVlan == intfType { - log.Info("YangToDb_intf_subintfs_xfmr - IntfTypeVlan") - return ifName, nil - } idx := pathInfo.Var("index") @@ -1378,10 +1181,7 @@ var DbToYangPath_intf_ip_path_xfmr PathXfmrDbToYangFunc = func(params XfmrDbToYg params.ygPathKeys[ifRoot+"/name"] = ifParts[0] - if params.tblName == "INTERFACE" || params.tblName == "VLAN_INTERFACE" || - params.tblName == "INTF_TABLE" || params.tblName == "MGMT_INTERFACE" || - params.tblName == "VLAN_SUB_INTERFACE" || params.tblName == "MGMT_INTF_TABLE" || - params.tblName == "PORTCHANNEL_INTERFACE" { + if params.tblName == "INTERFACE" || params.tblName == "INTF_TABLE" { addrPath := "/openconfig-if-ip:ipv4/addresses/address/ip" @@ -1397,16 +1197,13 @@ var DbToYangPath_intf_ip_path_xfmr PathXfmrDbToYangFunc = func(params XfmrDbToYg ipKey := strings.Split(dbKey, "/") - if strings.HasPrefix(params.tblKeyComp[0], "Vlan") { - return nil + if len(ifParts) > 1 { + params.ygPathKeys[subIf+"/index"] = ifParts[1] } else { - if len(ifParts) > 1 { - params.ygPathKeys[subIf+"/index"] = ifParts[1] - } else { - params.ygPathKeys[subIf+"/index"] = "0" - } - params.ygPathKeys[subIf+addrPath] = ipKey[0] + params.ygPathKeys[subIf+"/index"] = "0" } + params.ygPathKeys[subIf+addrPath] = ipKey[0] + } log.Infof("DbToYangPath_intf_ip_path_xfmr: tblName:%v dbKey:[%v] params.ygPathKeys: %v", params.tblName, dbKey, params.ygPathKeys) @@ -1500,9 +1297,6 @@ func handleAllIntfIPGetForTable(inParams XfmrParams, tblName string, isAppDb boo // YGOT filling for intfName, ipMapDB := range intfIpMap { - if strings.HasPrefix(intfName, "Vlan") { - continue - } var subIdxStr string var name string @@ -1559,12 +1353,7 @@ func ValidateIntfProvisionedForRelay(d *db.DB, ifName string, prefixIp string, e intTbl := IntfTypeTblMap[intfType] tblList = intTbl.cfgDb.intfTN - // for VLAN - DHCP info is stored in the VLAN Table - if intfType == IntfTypeVlan { - tblList = intTbl.cfgDb.portTN - } - - if entry == nil || intfType == IntfTypeVlan { + if entry == nil { ent, dbErr := d.GetEntry(&db.TableSpec{Name: tblList}, db.Key{Comp: []string{ifName}}) entry = &ent if dbErr != nil { @@ -1598,13 +1387,7 @@ func handleIntfIPGetByTargetURI(inParams XfmrParams, targetUriPath string, ifNam pathInfo := NewPathInfo(inParams.uri) ipAddr := pathInfo.Var("ip") - idx := pathInfo.Var("index") i32 := uint32(0) - if idx != "0" { - ifName = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&ifName, &idx) - i64, _ := strconv.ParseUint(idx, 10, 32) - i32 = uint32(i64) - } intfType, _, ierr := getIntfTypeByName(ifName) if intfType == IntfTypeUnset || ierr != nil { errStr := "Invalid interface type IntfTypeUnset" @@ -1776,7 +1559,7 @@ var DbToYang_intf_ip_addr_xfmr SubTreeXfmrDbToYang = func(inParams XfmrParams) e return nil } - intfTypeList := [5]E_InterfaceType{IntfTypeEthernet, IntfTypeMgmt, IntfTypePortChannel, IntfTypeLoopback, IntfTypeSubIntf} + intfTypeList := [1]E_InterfaceType{IntfTypeEthernet} // Get IP from all configDb table interfaces for i := 0; i < len(intfTypeList); i++ { @@ -1795,11 +1578,6 @@ var DbToYang_intf_ip_addr_xfmr SubTreeXfmrDbToYang = func(inParams XfmrParams) e var intfObj *ocbinds.OpenconfigInterfaces_Interfaces_Interface ifName = *(&uriIfName) - intfType, _, _ := getIntfTypeByName(ifName) - if IntfTypeVlan == intfType { - return nil - } - if strings.HasPrefix(targetUriPath, "/openconfig-interfaces:interfaces/interface/subinterfaces") { if intfsObj != nil && intfsObj.Interface != nil && len(intfsObj.Interface) > 0 { var ok bool = false @@ -1849,14 +1627,6 @@ var YangToDb_intf_ip_addr_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) ( log.Infof("YangToDb_intf_ip_addr_xfmr: Interface name retrieved from alias : %s is %s", ifName, *sonicIfName) ifName = *sonicIfName intfType, _, ierr := getIntfTypeByName(ifName) - if i32 > 0 { - intfType = IntfTypeSubIntf - ifName = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&ifName, &idx) - } - - if IntfTypeVxlan == intfType || IntfTypeVlan == intfType { - return subIntfmap, nil - } intfsObj := getIntfsRoot(inParams.ygRoot) if intfsObj == nil || len(intfsObj.Interface) < 1 { @@ -2104,8 +1874,16 @@ func validateIpOverlap(d *db.DB, intf string, ipPref string, tblName string, isI log.Info("IP: ", ipPref, " overlaps with ", key.Get(1), " of ", key.Get(0)) } - errStr := "IP " + ipPref + " overlaps with IP or IP Anycast " + key.Get(1) + " of Interface " + key.Get(0) - return "", errors.New(errStr) + //Handle IP overlap across different interface + _, _, ierr := getIntfTypeByName(key.Get(0)) + if ierr != nil { + log.Errorf("Extracting Interface type for Interface: %s failed!", key.Get(0)) + return "", ierr + } + if intf != key.Get(0) { + errStr := "IP " + ipPref + " overlaps with IP or IP Anycast " + key.Get(1) + " of Interface " + key.Get(0) + return "", errors.New(errStr) + } } } } @@ -2390,12 +2168,6 @@ func interfaceIPcount(tblName string, d *db.DB, intfName *string, ipCnt *int) er return nil } func check_if_delete_l3_intf_entry(d *db.DB, tblName string, ifName string, ipCnt int, intfEntry *db.Value) bool { - if strings.HasPrefix(ifName, VLAN) { - sagIpKey, _ := d.GetKeysPattern(&db.TableSpec{Name: "SAG"}, db.Key{Comp: []string{ifName, "*"}}) - if len(sagIpKey) != 0 { - return false - } - } if intfEntry == nil { entry, err := d.GetEntry(&db.TableSpec{Name: tblName}, db.Key{Comp: []string{ifName}}) if err != nil { @@ -2407,10 +2179,9 @@ func check_if_delete_l3_intf_entry(d *db.DB, tblName string, ifName string, ipCn if ipCnt == 0 && intfEntry.IsPopulated() { intfEntryMap := intfEntry.Field _, nullValPresent := intfEntryMap["NULL"] - _, natZoneValPresent := intfEntryMap["nat_zone"] /* Note: Unbinding shouldn't happen if VRF config is associated with interface. - Hence, we check for map length and only if either NULL or NAT value is present */ - if (len(intfEntryMap) == 1 && nullValPresent) || (len(intfEntryMap) == 2 && nullValPresent && natZoneValPresent) { + Hence, we check for map length and only if NULL value is present */ + if len(intfEntryMap) == 1 && nullValPresent { return true } } @@ -2421,7 +2192,6 @@ var Subscribe_intf_ip_addr_xfmr = func(inParams XfmrSubscInParams) (XfmrSubscOut if log.V(3) { log.Info("Entering Subscribe_intf_ip_addr_xfmr") } - var err error var result XfmrSubscOutParams pathInfo := NewPathInfo(inParams.uri) @@ -2429,152 +2199,10 @@ var Subscribe_intf_ip_addr_xfmr = func(inParams XfmrSubscInParams) (XfmrSubscOut log.Infof("Subscribe_intf_ip_addr_xfmr:- subscProc:%v URI: %s", inParams.subscProc, inParams.uri) log.Infof("Subscribe_intf_ip_addr_xfmr:- Target URI path: %s", origTargetUriPath) - - // When the subscribe subtree is invoked in the GET or CRUD context the inParams.subscProc is set to TRANSLATE_EXISTS - if inParams.subscProc == TRANSLATE_EXISTS { - // Defer the DB resource check done by infra by setting the virtual table to true. - // Resource checks are now performed within the DbToYang or YangToDb subtree callback. - result.isVirtualTbl = true - return result, nil - } - if inParams.subscProc == TRANSLATE_SUBSCRIBE { - isRoutedVlan := false - - ifBasePath := "/openconfig-interfaces:interfaces/interface" - targetUriPath := origTargetUriPath[len(ifBasePath):] - - if strings.HasPrefix(targetUriPath, "/subinterfaces") { - targetUriPath = targetUriPath[len("/subinterfaces/subinterface"):] - } else { - isRoutedVlan = true - targetUriPath = targetUriPath[len("/openconfig-vlan:routed-vlan"):] - } - - if strings.HasPrefix(targetUriPath, "/openconfig-if-ip:ipv4") { - targetUriPath = targetUriPath[len("/openconfig-if-ip:ipv4/addresses"):] - } else { - targetUriPath = targetUriPath[len("/openconfig-if-ip:ipv6/addresses"):] - } - - if targetUriPath == "" || targetUriPath == "/address" { - result.isVirtualTbl = true - log.Info("Subscribe_intf_ip_addr_xfmr:- result.isVirtualTbl: ", result.isVirtualTbl) - return result, err - } - - result.onChange = OnchangeEnable - result.nOpts = ¬ificationOpts{} - result.nOpts.pType = OnChange - result.isVirtualTbl = false - - uriIfName := pathInfo.Var("name") - tableName := "" - ipKey := "" - ifKey := "" - subIfKey := "*" - - if uriIfName == "" || uriIfName == "*" { - ifKey = "*" - } else { - sonicIfName := &uriIfName - ifKey = *sonicIfName - } - - addressConfigPath := "/address/config" - addressStatePath := "/address/state" - - idx := pathInfo.Var("index") - if ifKey != "" { - if idx == "0" { - intfType, _, _ := getIntfTypeByName(ifKey) - intTbl := IntfTypeTblMap[intfType] - if targetUriPath == addressStatePath { - tableName = intTbl.appDb.intfTN - } else { - tableName = intTbl.cfgDb.intfTN - } - } else if idx == "*" || idx == "" { - subIfKey = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&ifKey, &idx) - } else { - tableName = "VLAN_SUB_INTERFACE" - ifKey = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&ifKey, &idx) - } - } - - ipKey = pathInfo.Var("ip") - if ipKey == "" { - ipKey = "*" - } - - if ipKey != "*" { - ipKey = ipKey + "/*" - } - - log.Infof("path:%v ifKey:%v, ipKey:%v tbl:[%v]", origTargetUriPath, ifKey, ipKey, tableName) - - keyName := "" - if targetUriPath == addressConfigPath { - keyName = ifKey + "|" + ipKey - if tableName != "" { - result.dbDataMap = RedisDbSubscribeMap{db.ConfigDB: {tableName: {keyName: {}}}} - } else { - if isRoutedVlan { - result.dbDataMap = RedisDbSubscribeMap{db.ConfigDB: {"VLAN_INTERFACE": {keyName: {}}}} - } else { - subIfKeyName := subIfKey + "|" + ipKey - result.dbDataMap = RedisDbSubscribeMap{db.ConfigDB: {"INTERFACE": {keyName: {}}, - "MGMT_INTERFACE": {keyName: {}}, - "LOOPBACK_INTERFACE": {keyName: {}}, - "VLAN_SUB_INTERFACE": {subIfKeyName: {}}, - "PORTCHANNEL_INTERFACE": {keyName: {}}}} - } - } - } else if targetUriPath == addressStatePath { - keyName = ifKey + ":" + ipKey - if tableName != "" { - result.dbDataMap = RedisDbSubscribeMap{db.ApplDB: {tableName: {keyName: {KEY_COMP_CNT: "2", DEL_AS_UPDATE: "true"}}}} - } else { - if isRoutedVlan { - result.dbDataMap = RedisDbSubscribeMap{db.ApplDB: {"INTF_TABLE": {keyName: {KEY_COMP_CNT: "2", DEL_AS_UPDATE: "true"}}}} - } else { - result.dbDataMap = RedisDbSubscribeMap{db.ApplDB: {"INTF_TABLE": {keyName: {KEY_COMP_CNT: "2", DEL_AS_UPDATE: "true"}}, - "MGMT_INTF_TABLE": {keyName: {KEY_COMP_CNT: "2", DEL_AS_UPDATE: "true"}}}} - } - } - } - - log.Info("Subscribe_intf_ip_addr_xfmr:- result dbDataMap: ", result.dbDataMap) - log.Info("Subscribe_intf_ip_addr_xfmr:- result secDbDataMap: ", result.secDbDataMap) - - return result, err - } - - result.isVirtualTbl = false - - result.dbDataMap = make(RedisDbSubscribeMap) - uriIfName := pathInfo.Var("name") - idx := pathInfo.Var("index") - sonicIfName := &uriIfName - keyName := *sonicIfName - - if keyName != "" { - intfType, _, _ := getIntfTypeByName(keyName) - intTbl := IntfTypeTblMap[intfType] - tblName := intTbl.cfgDb.intfTN - if idx != "" && idx != "0" { - tblName = "VLAN_SUB_INTERFACE" - keyName = *utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(&keyName, &idx) - } - result.dbDataMap = RedisDbSubscribeMap{db.ConfigDB: {tblName: {keyName: {}}}} - } - log.Info("Returning Subscribe_intf_ip_addr_xfmr, result:", result) - result.needCache = true - result.nOpts = new(notificationOpts) - result.nOpts.mInterval = 15 - result.nOpts.pType = OnChange - log.Info("Returning Subscribe_intf_ip_addr_xfmr, result:", result) - return result, err - + // Defer the DB resource check done by infra by setting the virtual table to true. + // Resource checks are now performed within the DbToYang or YangToDb subtree callback. + result.isVirtualTbl = true + return result, nil } // YangToDb_subintf_ipv6_tbl_key_xfmr is a YangToDB Key transformer for IPv6 config. @@ -2591,17 +2219,7 @@ var YangToDb_subintf_ipv6_tbl_key_xfmr KeyXfmrYangToDb = func(inParams XfmrParam if log.V(3) { log.Info("inParams.requestUri: ", inParams.requestUri) } - idx := pathInfo.Var("index") - var i32 uint32 - i32 = 0 - if idx != "" { - i64, _ := strconv.ParseUint(idx, 10, 32) - i32 = uint32(i64) - } inst_key = ifName - if i32 > 0 { - inst_key = ifName + "." + idx - } log.Info("Exiting YangToDb_subintf_ipv6_tbl_key_xfmr, key ", inst_key) return inst_key, err } @@ -2625,16 +2243,9 @@ var YangToDb_ipv6_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (ma res_map := make(map[string]string) pathInfo := NewPathInfo(inParams.uri) ifUIName := pathInfo.Var("name") - idx := pathInfo.Var("index") - var i32 uint32 - i32 = 0 - if idx != "" { - i64, _ := strconv.ParseUint(idx, 10, 32) - i32 = uint32(i64) - } intfType, _, ierr := getIntfTypeByName(ifUIName) - if ierr != nil || intfType == IntfTypeUnset || intfType == IntfTypeVxlan || intfType == IntfTypeMgmt { + if ierr != nil || intfType == IntfTypeUnset { return res_map, errors.New("YangToDb_ipv6_enabled_xfmr, Error: Unsupported Interface: " + ifUIName) } @@ -2650,7 +2261,7 @@ var YangToDb_ipv6_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (ma // Vlan Interface (routed-vlan) contains only one Key "ifname" // For all other interfaces (subinterfaces/subintfaces) will have 2 keys "ifname" & "subintf-index" - if len(pathInfo.Vars) < 2 && intfType != IntfTypeVlan { + if len(pathInfo.Vars) < 2 { return res_map, errors.New("YangToDb_ipv6_enabled_xfmr, Error: Invalid Key length") } @@ -2662,10 +2273,6 @@ var YangToDb_ipv6_enabled_xfmr FieldXfmrYangToDb = func(inParams XfmrParams) (ma intTbl := IntfTypeTblMap[intfType] tblName := intTbl.cfgDb.intfTN - if i32 > 0 { - tblName = "VLAN_SUB_INTERFACE" - ifName = utils.GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(ifName, &idx) - } ipMap, _ := getIntfIpByName(inParams.d, tblName, *ifName, true, true, "") var enStr string subOpMap := make(map[db.DBNum]map[string]map[string]db.Value) diff --git a/translib/utils/utils.go b/translib/utils/utils.go index d2aee1656..cc79ae0c7 100644 --- a/translib/utils/utils.go +++ b/translib/utils/utils.go @@ -21,7 +21,6 @@ package utils import ( "fmt" - //"github.com/Azure/sonic-mgmt-common/translib/db" "github.com/Azure/sonic-mgmt-common/cvl" "github.com/Azure/sonic-mgmt-common/translib/db" log "github.com/golang/glog" @@ -65,9 +64,3 @@ func RemoveElement(sl []string, str string) []string { } return sl } -func GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID(parentIf *string, subId *string) *string { - uiName := *parentIf + "." + *subId - key := *(&uiName) - log.V(3).Infof("GetSubInterfaceDBKeyfromParentInterfaceAndSubInterfaceID %s + %s => %s", *parentIf, *subId, key) - return &key -} From 388820276c78b5860becb80760f6e4529cba36a3 Mon Sep 17 00:00:00 2001 From: Satoru-Shinohara Date: Mon, 19 Feb 2024 17:13:25 -0500 Subject: [PATCH 08/13] UT Tests for openconfig-interfaces (Top-Level Interfaces + Ethernet) --- .../transformer/interfaces_openconfig_test.go | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 translib/transformer/interfaces_openconfig_test.go diff --git a/translib/transformer/interfaces_openconfig_test.go b/translib/transformer/interfaces_openconfig_test.go new file mode 100644 index 000000000..1e024a7c6 --- /dev/null +++ b/translib/transformer/interfaces_openconfig_test.go @@ -0,0 +1,204 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright 2023 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. // +// // +//////////////////////////////////////////////////////////////////////////////// + +//go:build testapp +// +build testapp + +package transformer_test + +import ( + //"errors" + "github.com/Azure/sonic-mgmt-common/translib/tlerr" + "testing" + "time" +) + +func Test_openconfig_interfaces(t *testing.T) { + var url, url_input_body_json string + + t.Log("\n\n+++++++++++++ CONFIGURING INTERFACES ATTRIBUTES ++++++++++++") + t.Log("\n\n--- PATCH interfaces config---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config" + url_input_body_json = "{\"openconfig-interfaces:config\": { \"mtu\": 8900, \"description\": \"UT_Interface\", \"enabled\": false}}" + t.Run("Test PATCH on interface config", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH interfaces config ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config" + expected_get_json := "{\"openconfig-interfaces:config\": {\"description\": \"UT_Interface\", \"enabled\": false, \"mtu\": 8900, \"name\": \"Ethernet0\"}}" + t.Run("Test GET on interface config", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- PATCH interface leaf nodes---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config/enabled" + url_input_body_json = "{\"openconfig-interfaces:enabled\": true}" + t.Run("Test PATCH on interface enabled", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config/mtu" + url_input_body_json = "{\"openconfig-interfaces:mtu\": 9000}" + t.Run("Test PATCH on interface mtu", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config/description" + url_input_body_json = "{\"openconfig-interfaces:description\": \"UT_LEAF\"}" + t.Run("Test PATCH on interface description", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH interface leaf nodes ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/state" + expected_get_json = "{\"openconfig-interfaces:state\": { \"admin-status\": \"UP\", \"description\": \"UT_LEAF\", \"enabled\": true, \"mtu\": 9000, \"name\": \"Ethernet0\"}}" + t.Run("Test GET on interface state", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- DELETE at interface enabled ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config/enabled" + t.Run("Test DELETE on interface enabled", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify DELETE at interface enabled ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config/enabled" + expected_get_json = "{\"openconfig-interfaces:enabled\": false}" + t.Run("Test GET on interface config", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- DELETE at interface mtu ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config/mtu" + t.Run("Test DELETE on interface mtu", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify DELETE at interface mtu ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config/mtu" + expected_get_json = "{\"openconfig-interfaces:mtu\": 9100}" + t.Run("Test GET on interface config", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- DELETE at interfaces container ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]" + err_str := "Physical Interface: Ethernet0 cannot be deleted" + expected_err := tlerr.InvalidArgsError{Format: err_str} + t.Run("Test DELETE on interface container", processDeleteRequest(url, true, expected_err)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- DELETE at interface description ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config/description" + t.Run("Test DELETE on interface description", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify DELETE at interface description ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/config/description" + err_str = "Resource not found" + expected_err_invalid := tlerr.NotFoundError{Format: err_str} + t.Run("Test GET on deleted description", processGetRequest(url, nil, "", true, expected_err_invalid)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- PATCH interface ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]" + url_input_body_json = "{\"openconfig-interfaces:interface\":[{\"name\":\"Ethernet0\",\"config\":{\"name\":\"Ethernet0\",\"mtu\":9000,\"description\":\"UT_TOP\",\"enabled\":true}}]}" + t.Run("Test PATCH on interface", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH interface ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/state" + expected_get_json = "{\"openconfig-interfaces:state\": { \"admin-status\": \"UP\", \"description\": \"UT_TOP\", \"enabled\": true, \"mtu\": 9000, \"name\": \"Ethernet0\"}}" + t.Run("Test GET on interface state", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) +} + +func Test_openconfig_ethernet(t *testing.T) { + var url, url_input_body_json string + + t.Log("\n\n+++++++++++++ CONFIGURING ETHERNET ATTRIBUTES ++++++++++++") + t.Log("\n\n--- PATCH ethernet auto-neg and port-speed ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config/port-speed" + url_input_body_json = "{\"openconfig-if-ethernet:port-speed\":\"SPEED_40GB\"}" + t.Run("Test PATCH on ethernet port-speed", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config/auto-negotiate" + url_input_body_json = "{\"openconfig-if-ethernet:auto-negotiate\":true}" + t.Run("Test PATCH on ethernet auto-neg", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH ethernet ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet" + expected_get_json := "{\"openconfig-if-ethernet:ethernet\": {\"config\": {\"auto-negotiate\": true,\"port-speed\": \"openconfig-if-ethernet:SPEED_40GB\"},\"state\": {\"auto-negotiate\": true,\"port-speed\": \"openconfig-if-ethernet:SPEED_40GB\"}}}" + t.Run("Test GET on ethernet", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- DELETE at ethernet port-speed---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config/port-speed" + err_str := "DELETE request not allowed for port-speed" + expected_err := tlerr.NotSupportedError{Format: err_str} + t.Run("Test DELETE on ethernet port-speed", processDeleteRequest(url, true, expected_err)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- DELETE at ethernet container ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet" + t.Run("Test DELETE on ethernet", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify DELETE at ethernet container ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/state" + expected_get_json = "{\"openconfig-if-ethernet:state\": {\"auto-negotiate\": true,\"port-speed\": \"openconfig-if-ethernet:SPEED_40GB\"}}" + t.Run("Test GET on ethernet state", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- DELETE at ethernet auto-negotiate ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config/auto-negotiate" + t.Run("Test DELETE on ethernet auto-negotiate", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify DELETE at ethernet auto-negotiate ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config/auto-negotiate" + err_str = "auto-negotiate not set" + expected_err_invalid := tlerr.InvalidArgsError{Format: err_str} + t.Run("Test GET on deleted auto-negotiate", processGetRequest(url, nil, "", true, expected_err_invalid)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH port-speed to set auto-neg ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config/port-speed" + url_input_body_json = "{\"openconfig-if-ethernet:port-speed\":\"SPEED_10GB\"}" + time.Sleep(1 * time.Second) + t.Run("Test PATCH on ethernet port-speed", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH on port-speed to set auto-neg ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config" + expected_get_json = "{\"openconfig-if-ethernet:config\": {\"auto-negotiate\": false,\"port-speed\": \"openconfig-if-ethernet:SPEED_10GB\"}}" + t.Run("Test GET on ethernet config", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- DELETE at ethernet config ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config" + t.Run("Test DELETE on ethernet config", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify DELETE at ethernet config ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config/auto-negotiate" + expected_get_json = "{\"openconfig-if-ethernet:auto-negotiate\": false}" + t.Run("Test GET on auto-negotiate", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify DELETE at ethernet config ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/openconfig-if-ethernet:ethernet/config/port-speed" + expected_get_json = "{\"openconfig-if-ethernet:port-speed\": \"openconfig-if-ethernet:SPEED_10GB\"}" + t.Run("Test GET on port-speed", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + +} From ca4bd9ec29e159598119dadd634d2745cb1f5d61 Mon Sep 17 00:00:00 2001 From: Nikita Agarwal Date: Tue, 20 Feb 2024 04:53:04 -0800 Subject: [PATCH 09/13] Adding automation file for subinterfaces. --- .../transformer/interfaces_openconfig_test.go | 386 ++++++++++++++++++ 1 file changed, 386 insertions(+) create mode 100644 translib/transformer/interfaces_openconfig_test.go diff --git a/translib/transformer/interfaces_openconfig_test.go b/translib/transformer/interfaces_openconfig_test.go new file mode 100644 index 000000000..f7d8c50d7 --- /dev/null +++ b/translib/transformer/interfaces_openconfig_test.go @@ -0,0 +1,386 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// Copyright 2023 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. // +// // +//////////////////////////////////////////////////////////////////////////////// + +//go:build testapp +// +build testapp + +package transformer_test + +import ( + "github.com/Azure/sonic-mgmt-common/translib/tlerr" + "testing" + "time" +) + +func Test_openconfig_subintf(t *testing.T) { + var url, url_input_body_json string + + t.Log("\n\n+++++++++++++ CONFIGURING AND REMOVING IPv4 ADDRESS AT SUBINTERFACES ++++++++++++") + t.Log("\n\n--- TC 1: Delete/Clear existing IPv4 address on Ethernet0 ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" + t.Run("Test Delete/Clear IPv4 on subinterfaces", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Get/Verify IPv4 address at subinterfaces ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json := "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + t.Run("Test Get IPv4 address at subinterfaces", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- PATCH IPv4 address at addresses level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" + url_input_body_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"ip\": \"4.4.4.4\", \"openconfig-if-ip:config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}" + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set IPv4 address on subinterfaces addresses", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify IPv4 address at subinterfaces level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv4\": {\"addresses\": {\"address\": [{\"config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}, \"ip\": \"4.4.4.4\", \"state\":{ \"family\":\"ipv4\", \"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + t.Run("Test Get/Verify Patch IPv4 address at subinterfaces level", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Delete IPv4 address at subinterfaces level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + t.Run("Test Delete IPv4 address at subinterfaces level", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv4 address at subinterfaces level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + t.Run("Test/Verify Get at subinterfaces", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------- + + t.Log("\n\n--- Get at subinterfaces/subinterface[index=0] level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]" + expected_get_json = "{\"openconfig-interfaces:subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}" + t.Run("Test Get at subinterface[index=0]", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- PATCH IPv4 address at addresses level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" + url_input_body_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"ip\": \"4.4.4.4\", \"openconfig-if-ip:config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}" + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set IPv4 address at subinterfaces addresses", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify IPv4 address at subinterfaces/subinterface[index=0] level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]" + expected_get_json = "{\"openconfig-interfaces:subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv4\": {\"addresses\": {\"address\": [{\"config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}, \"ip\": \"4.4.4.4\", \"state\":{ \"family\":\"ipv4\", \"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}" + t.Run("Test Get/Verify Patch IPv4 address at subinterface[index=0]", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Negative test: Verify IPv4 address at incorrect subinterfaces/subinterface[index=1] level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=1]" + expected_get_json = "{}" + t.Run("Negative test: Test Get IPv4 address at incorrect subinterface[index=1]", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Delete IPv4 address at subinterfaces/subinterface[index=0] level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]" + t.Run("Test Delete IPv4 address at subinterface[index=0] level", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv4 address at subinterfaces/subinterface[index=0] level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]" + expected_get_json = "{\"openconfig-interfaces:subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}" + t.Run("Test Get/Verify Delete IPv4 address at subinterface[index=0]", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv4 address at subinterfaces level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + t.Run("Test Get/Verify Delete IPv4 address at subinterfaces", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- PATCH IPv4 address at addresses level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" + url_input_body_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"ip\": \"4.4.4.4\", \"openconfig-if-ip:config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}" + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set IPv4 address on subinterfaces addresses", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH IPv4 address at addresses level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" + expected_get_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}, \"ip\": \"4.4.4.4\", \"state\":{ \"family\":\"ipv4\", \"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}" + t.Run("Test Get/Verify Patch IPv4 address at subinterfaces ipv4/addresses", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Delete IPv4 address at addresses ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" + t.Run("Test Delete IPv4 address on subinterfaces addresses", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv4 address at subinterfaces addresses level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" + expected_get_json = "{}" + t.Run("Test Get/Verify Delete IPv4 address at subinterfaces addresses", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv4 address at subinterfaces level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + t.Run("Test Get/Verify Delete at subinterfaces", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- PATCH IPv4 address at addresses level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" + url_input_body_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"ip\": \"4.4.4.4\", \"openconfig-if-ip:config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}" + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set IPv4 address on subinterfaces addresses", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH IPv4 address at addresses/address/config level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses/address[ip=4.4.4.4]/config" + expected_get_json = "{\"openconfig-if-ip:config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}}" + t.Run("Test Get IPv4 address at subinterfaces ipv4/config", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- Verify Get at interfaces/interface[name=Ethernet0] ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]" + expected_get_json = "{\"openconfig-interfaces:interface\":[{\"config\":{\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"openconfig-if-ethernet:ethernet\":{\"config\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"},\"state\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"}},\"name\":\"Ethernet0\",\"state\":{\"admin-status\":\"UP\",\"description\":\"\",\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"subinterfaces\":{\"subinterface\":[{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv4\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"4.4.4.4\",\"prefix-length\":24},\"ip\":\"4.4.4.4\",\"state\":{\"family\":\"ipv4\",\"ip\":\"4.4.4.4\",\"prefix-length\":24}}]}},\"openconfig-if-ip:ipv6\":{\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}}]}" + t.Run("Test Get at interfaces/interface[name=Ethernet0]", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- Duplicate IP test: PATCH existing IPv4 address on another interface ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet8]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" + url_input_body_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"ip\": \"4.4.4.4\", \"openconfig-if-ip:config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}" + err_str := "IP 4.4.4.4/24 overlaps with IP or IP Anycast 4.4.4.4/24 of Interface Ethernet0" + expected_err := tlerr.InvalidArgsError{Format: err_str} + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set duplicate IPv4 address on another interface", processSetRequest(url, url_input_body_json, "PATCH", true, expected_err)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- Negative test: Delete IPv4 container ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/ipv4" + err_str = "DELETE operation not allowed on this container" + expected_err_2 := tlerr.NotSupportedError{Format: err_str} + time.Sleep(1 * time.Second) + t.Run("Test Delete IPv4 container not allowed", processDeleteRequest(url, true, expected_err_2)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- Delete IPv4 address ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses/address[ip=4.4.4.4]" + t.Run("Test Delete IPv4 address on subinterfaces address", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv4 address at subinterfaces level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + t.Run("Test Get/Verify Delete IPv4 address at subinterfaces", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n+++++++++++++ DONE CONFIGURING AND REMOVING IPV4 ADDRESSES ON SUBINTERFACES ++++++++++++") + + t.Log("\n\n+++++++++++++ CONFIGURING AND REMOVING IPv6 ADDRESS AT SUBINTERFACES ++++++++++++") + t.Log("\n\n--- Delete/Clear IPv6 address ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses" + t.Run("Test Delete/Clear IPv6 address on subinterfaces addresses", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Get IPv6 address at subinterfaces ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + t.Run("Test Get IPv6 address at subinterfaces", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- PATCH IPv6 address at subinterfaces addresses ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses" + url_input_body_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"ip\": \"a::e\", \"openconfig-if-ip:config\": {\"ip\": \"a::e\", \"prefix-length\": 64}}]}}" + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set IPv6 address on subinterfaces addresses", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify IPv6 address at subinterfaces level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\":{\"subinterface\":[{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv6\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"family\":\"ipv6\",\"ip\":\"a::e\",\"prefix-length\":64}}]},\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}}" + t.Run("Test Get/Verify Patch IPv6 address at subinterfaces level", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Delete IPv6 address at subinterfaces ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + t.Run("Test Delete IPv6 address at subinterfaces", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv6 address at subinterfaces ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + t.Run("Test Get/Verify Delete IPv6 address at subinterfaces", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- PATCH IPv6 address at addresses ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses" + url_input_body_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"ip\": \"a::e\", \"openconfig-if-ip:config\": {\"ip\": \"a::e\", \"prefix-length\": 64}}]}}" + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set IPv6 address on subinterfaces addresses", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH IPv6 address at subinterface level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface" + expected_get_json = "{\"openconfig-interfaces:subinterface\": [{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv6\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"family\":\"ipv6\",\"ip\":\"a::e\",\"prefix-length\":64}}]},\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}" + t.Run("Test Get/Verify Patch IPv6 address at subinterface", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Delete IPv6 address at subinterface ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface" + t.Run("Test Delete IPv6 address at subinterface", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv6 address at subinterface ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface" + expected_get_json = "{\"openconfig-interfaces:subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}" + t.Run("Test Get/Verify Delete IPv6 address at subinterface", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- PATCH IPv6 address at addresses ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses" + url_input_body_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"ip\": \"a::e\", \"openconfig-if-ip:config\": {\"ip\": \"a::e\", \"prefix-length\": 64}}]}}" + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set IPv6 address on subinterfaces addresses", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH IPv6 address at addresses level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses" + expected_get_json = "{\"openconfig-if-ip:addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"family\":\"ipv6\",\"ip\":\"a::e\",\"prefix-length\":64}}]}}" + t.Run("Test Get/Verify Patch IPv6 address at subinterfaces addresses", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Delete IPv6 address at subinterfaces addresses level---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses" + t.Run("Test Delete IPv6 address at subinterfaces addresses level", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv6 address at subinterfaces addresses ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/ipv6/addresses" + expected_get_json = "{}" + t.Run("Test Get/Verify Delete IPv6 address at subinterfaces addresses", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- PATCH IPv6 address at addresses ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses" + url_input_body_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"ip\": \"a::e\", \"openconfig-if-ip:config\": {\"ip\": \"a::e\", \"prefix-length\": 64}}]}}" + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set IPv6 address on subinterfaces addresses", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH IPv6 address at subinterfaces ipv6/config level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses/address[ip=a::e]/config" + expected_get_json = "{\"openconfig-if-ip:config\": {\"ip\": \"a::e\", \"prefix-length\": 64}}" + t.Run("Test Get/Verify Patch IPv6 address at subinterfaces ipv6/config", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- Verify Get at interfaces/interface[name=Ethernet0] ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]" + expected_get_json = "{\"openconfig-interfaces:interface\":[{\"config\":{\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"openconfig-if-ethernet:ethernet\":{\"config\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"},\"state\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"}},\"name\":\"Ethernet0\",\"state\":{\"admin-status\":\"UP\",\"description\":\"\",\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"subinterfaces\":{\"subinterface\":[{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv6\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"family\":\"ipv6\",\"ip\":\"a::e\",\"prefix-length\":64}}]},\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}}]}" + + t.Run("Test Get at interfaces/interface[name=Ethernet0]", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- Negative test: Delete IPv6 config container ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/config" + err_str = "Delete not allowed at this container" + expected_err_2 = tlerr.NotSupportedError{Format: err_str} + time.Sleep(1 * time.Second) + t.Run("Test Delete IPv6 config", processDeleteRequest(url, true, expected_err_2)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- Delete IPv6 address ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses/address[ip=a::e]" + t.Run("Test Delete/Clear IPv6 address on subinterfaces address", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- Verify Get IPv6 address after Delete at subinterfaces ipv6/config level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses/address[ip=a::e]/config" + err_str = "Resource not found" + expected_err_invalid := tlerr.NotFoundError{Format: err_str} + time.Sleep(1 * time.Second) + t.Run("Test Get/Verify Patch IPv6 address after Delete at subinterfaces ipv6/config", processGetRequest(url, nil, "", true, expected_err_invalid)) + time.Sleep(1 * time.Second) + + //------------------------------------------------------------------------------------------------------------------------------------ + + t.Log("\n\n--- Verify Delete IPv6 address at subinterfaces ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + t.Run("Test Get IPv6 address at subinterfaces", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n+++++++++++++ DONE CONFIGURING AND REMOVING IPV6 ADDRESSES ON SUBINTERFACES ++++++++++++") + + t.Log("\n\n+++++++++++++ ENABLE AND DISABLE IPV6 LINK LOCAL ON SUBINTERFACES ++++++++++++") + t.Log("\n\n--- Get IPv6 link local value (enabled) at config level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/ipv6/config" + expected_get_json = "{\"openconfig-if-ip:config\": {\"enabled\": false}}" + t.Run("Test Get IPv6 link local at subinterfaces config level", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- PATCH/Enable ipv6 link local at config/enabled level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/ipv6/config/enabled" + url_input_body_json = "{\"openconfig-if-ip:enabled\": true}" + time.Sleep(1 * time.Second) + t.Run("Test Patch/Set/Enable IPv6 link local on subinterfaces config", processSetRequest(url, url_input_body_json, "PATCH", false, nil)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify PATCH IPv6 link local at config/enabled level ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/ipv6/config/enabled" + expected_get_json = "{\"openconfig-if-ip:enabled\": true}" + time.Sleep(1 * time.Second) + t.Run("Test Get/Verify Patch IPv6 link local at subinterfaces config", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Delete/Disable IPv6 link local ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/ipv6/config/enabled" + t.Run("Test Delete/Disable IPv6 link local on subinterfaces config", processDeleteRequest(url, true)) + time.Sleep(1 * time.Second) + + t.Log("\n\n--- Verify Delete IPv6 link local ---") + url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/ipv6/config" + expected_get_json = "{\"openconfig-if-ip:config\": {\"enabled\": false}}" + t.Run("Test Get/Verify Delete IPv6 link local at subinterfaces config level", processGetRequest(url, nil, expected_get_json, false)) + time.Sleep(1 * time.Second) + + t.Log("\n\n+++++++++++++ DONE ENABLING AND DISABLING IPV6 LINK LOCAL ON SUBINTERFACES ++++++++++++") +} From 0ba14029ec13e4757cf05144c0f65d0fef747e39 Mon Sep 17 00:00:00 2001 From: Nikita Agarwal Date: Tue, 20 Feb 2024 15:41:56 -0800 Subject: [PATCH 10/13] Addressing review comments. Removed family attribute from OC Yang. --- models/yang/openconfig-if-ip.yang | 8 -------- translib/transformer/xfmr_intf.go | 31 +++---------------------------- 2 files changed, 3 insertions(+), 36 deletions(-) diff --git a/models/yang/openconfig-if-ip.yang b/models/yang/openconfig-if-ip.yang index 47debfa62..8680d2dc8 100644 --- a/models/yang/openconfig-if-ip.yang +++ b/models/yang/openconfig-if-ip.yang @@ -391,10 +391,6 @@ module openconfig-if-ip { "The length of the subnet prefix."; } - leaf family { - type string; - description "Indicates whether the IP address is IPv4 or IPv6"; - } } grouping ipv4-neighbor-config { @@ -507,10 +503,6 @@ module openconfig-if-ip { description "The length of the subnet prefix."; } - leaf family { - type string; - description "Indicates whether the IP address is IPv4 or IPv6"; - } } grouping ipv6-address-state { diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go index 3e7f94eb6..192d739c7 100644 --- a/translib/transformer/xfmr_intf.go +++ b/translib/transformer/xfmr_intf.go @@ -1375,12 +1375,9 @@ func convertIpMapToOC(intfIpMap map[string]db.Value, ifInfo *ocbinds.OpenconfigI v4Address.Ip = ipStr prfxLen := new(uint8) *prfxLen = ipNetB.Bits() - ipv4Str := new(string) - *ipv4Str = "ipv4" if isState { v4Address.State.Ip = ipStr v4Address.State.PrefixLength = prfxLen - v4Address.State.Family = ipv4Str } else { v4Address.Config.Ip = ipStr v4Address.Config.PrefixLength = prfxLen @@ -1393,12 +1390,9 @@ func convertIpMapToOC(intfIpMap map[string]db.Value, ifInfo *ocbinds.OpenconfigI v6Address.Ip = ipStr prfxLen := new(uint8) *prfxLen = ipNetB.Bits() - ipv6Str := new(string) - *ipv6Str = "ipv6" if isState { v6Address.State.Ip = ipStr v6Address.State.PrefixLength = prfxLen - v6Address.State.Family = ipv6Str } else { v6Address.Config.Ip = ipStr v6Address.Config.PrefixLength = prfxLen @@ -1597,17 +1591,6 @@ var YangToDb_intf_ip_addr_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) ( return subIntfmap, err } log.Info("prefix:=", *addr.Config.PrefixLength) - if addr.Config.Family == nil { - addr.Config.Family = new(string) - *addr.Config.Family = "ipv4" - - } else if *addr.Config.Family == "ipv6" { - log.Error("Incorrect family ipv6!") - errStr := "IPv4 Family not present" - err = tlerr.InvalidArgsError{Format: errStr} - return subIntfmap, err - } - log.Info("family:=", *addr.Config.Family) ipPref := *addr.Config.Ip + "/" + strconv.Itoa(int(*addr.Config.PrefixLength)) /* Check for IP overlap */ @@ -1632,6 +1615,7 @@ var YangToDb_intf_ip_addr_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) ( } intf_key := intf_intf_tbl_key_gen(ifName, *addr.Config.Ip, int(*addr.Config.PrefixLength), "|") + m["family"] = "IPv4" value := db.Value{Field: m} if _, ok := subIntfmap[tblName]; !ok { @@ -1660,17 +1644,6 @@ var YangToDb_intf_ip_addr_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) ( return subIntfmap, err } log.Info("Ipv6 prefix:=", *addr.Config.PrefixLength) - if addr.Config.Family == nil { - addr.Config.Family = new(string) - *addr.Config.Family = "ipv6" - - } else if *addr.Config.Family == "ipv4" { - log.Error("Incorrect family!") - errStr := "IPv6 Family not present" - err = tlerr.InvalidArgsError{Format: errStr} - return subIntfmap, err - } - log.Info("family:=", *addr.Config.Family) /* Check for IPv6 overlap */ ipPref := *addr.Config.Ip + "/" + strconv.Itoa(int(*addr.Config.PrefixLength)) @@ -1680,6 +1653,8 @@ var YangToDb_intf_ip_addr_xfmr SubTreeXfmrYangToDb = func(inParams XfmrParams) ( intf_key := intf_intf_tbl_key_gen(ifName, *addr.Config.Ip, int(*addr.Config.PrefixLength), "|") + m["family"] = "IPv6" + value := db.Value{Field: m} if _, ok := subIntfmap[tblName]; !ok { subIntfmap[tblName] = make(map[string]db.Value) From 07c6f21960bcb8cdf083b87e523394d41596e129 Mon Sep 17 00:00:00 2001 From: Nikita Agarwal Date: Tue, 20 Feb 2024 23:17:55 -0800 Subject: [PATCH 11/13] Updating automation files. Removed family attribute. --- .../transformer/interfaces_openconfig_test.go | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/translib/transformer/interfaces_openconfig_test.go b/translib/transformer/interfaces_openconfig_test.go index f7d8c50d7..eab1f914a 100644 --- a/translib/transformer/interfaces_openconfig_test.go +++ b/translib/transformer/interfaces_openconfig_test.go @@ -27,7 +27,7 @@ import ( "time" ) -func Test_openconfig_subintf(t *testing.T) { +func Test_openconfig_subintf_ipv4(t *testing.T) { var url, url_input_body_json string t.Log("\n\n+++++++++++++ CONFIGURING AND REMOVING IPv4 ADDRESS AT SUBINTERFACES ++++++++++++") @@ -51,7 +51,7 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Verify IPv4 address at subinterfaces level ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" - expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv4\": {\"addresses\": {\"address\": [{\"config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}, \"ip\": \"4.4.4.4\", \"state\":{ \"family\":\"ipv4\", \"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv4\": {\"addresses\": {\"address\": [{\"config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}, \"ip\": \"4.4.4.4\", \"state\":{\"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" t.Run("Test Get/Verify Patch IPv4 address at subinterfaces level", processGetRequest(url, nil, expected_get_json, false)) time.Sleep(1 * time.Second) @@ -83,7 +83,7 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Verify IPv4 address at subinterfaces/subinterface[index=0] level ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]" - expected_get_json = "{\"openconfig-interfaces:subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv4\": {\"addresses\": {\"address\": [{\"config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}, \"ip\": \"4.4.4.4\", \"state\":{ \"family\":\"ipv4\", \"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}" + expected_get_json = "{\"openconfig-interfaces:subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv4\": {\"addresses\": {\"address\": [{\"config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}, \"ip\": \"4.4.4.4\", \"state\":{\"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}" t.Run("Test Get/Verify Patch IPv4 address at subinterface[index=0]", processGetRequest(url, nil, expected_get_json, false)) time.Sleep(1 * time.Second) @@ -121,7 +121,7 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Verify PATCH IPv4 address at addresses level ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/addresses" - expected_get_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}, \"ip\": \"4.4.4.4\", \"state\":{ \"family\":\"ipv4\", \"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}" + expected_get_json = "{\"openconfig-if-ip:addresses\": {\"address\": [{\"config\": {\"ip\": \"4.4.4.4\", \"prefix-length\": 24}, \"ip\": \"4.4.4.4\", \"state\":{ \"ip\": \"4.4.4.4\", \"prefix-length\": 24}}]}}" t.Run("Test Get/Verify Patch IPv4 address at subinterfaces ipv4/addresses", processGetRequest(url, nil, expected_get_json, false)) time.Sleep(1 * time.Second) @@ -161,7 +161,7 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Verify Get at interfaces/interface[name=Ethernet0] ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]" - expected_get_json = "{\"openconfig-interfaces:interface\":[{\"config\":{\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"openconfig-if-ethernet:ethernet\":{\"config\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"},\"state\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"}},\"name\":\"Ethernet0\",\"state\":{\"admin-status\":\"UP\",\"description\":\"\",\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"subinterfaces\":{\"subinterface\":[{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv4\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"4.4.4.4\",\"prefix-length\":24},\"ip\":\"4.4.4.4\",\"state\":{\"family\":\"ipv4\",\"ip\":\"4.4.4.4\",\"prefix-length\":24}}]}},\"openconfig-if-ip:ipv6\":{\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}}]}" + expected_get_json = "{\"openconfig-interfaces:interface\":[{\"config\":{\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"openconfig-if-ethernet:ethernet\":{\"config\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"},\"state\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"}},\"name\":\"Ethernet0\",\"state\":{\"admin-status\":\"UP\",\"description\":\"\",\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"subinterfaces\":{\"subinterface\":[{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv4\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"4.4.4.4\",\"prefix-length\":24},\"ip\":\"4.4.4.4\",\"state\":{\"ip\":\"4.4.4.4\",\"prefix-length\":24}}]}},\"openconfig-if-ip:ipv6\":{\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}}]}" t.Run("Test Get at interfaces/interface[name=Ethernet0]", processGetRequest(url, nil, expected_get_json, false)) time.Sleep(1 * time.Second) @@ -200,6 +200,9 @@ func Test_openconfig_subintf(t *testing.T) { time.Sleep(1 * time.Second) t.Log("\n\n+++++++++++++ DONE CONFIGURING AND REMOVING IPV4 ADDRESSES ON SUBINTERFACES ++++++++++++") +} +func Test_openconfig_subintf_ipv6(t *testing.T) { + var url, url_input_body_json string t.Log("\n\n+++++++++++++ CONFIGURING AND REMOVING IPv6 ADDRESS AT SUBINTERFACES ++++++++++++") t.Log("\n\n--- Delete/Clear IPv6 address ---") @@ -209,7 +212,7 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Get IPv6 address at subinterfaces ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" - expected_get_json = "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" + expected_get_json := "{\"openconfig-interfaces:subinterfaces\": {\"subinterface\": [{\"config\": {\"index\": 0}, \"index\": 0, \"openconfig-if-ip:ipv6\": {\"config\": {\"enabled\": false}}, \"state\": {\"index\": 0}}]}}" t.Run("Test Get IPv6 address at subinterfaces", processGetRequest(url, nil, expected_get_json, false)) time.Sleep(1 * time.Second) @@ -222,7 +225,7 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Verify IPv6 address at subinterfaces level ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces" - expected_get_json = "{\"openconfig-interfaces:subinterfaces\":{\"subinterface\":[{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv6\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"family\":\"ipv6\",\"ip\":\"a::e\",\"prefix-length\":64}}]},\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}}" + expected_get_json = "{\"openconfig-interfaces:subinterfaces\":{\"subinterface\":[{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv6\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"ip\":\"a::e\",\"prefix-length\":64}}]},\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}}" t.Run("Test Get/Verify Patch IPv6 address at subinterfaces level", processGetRequest(url, nil, expected_get_json, false)) time.Sleep(1 * time.Second) @@ -248,7 +251,7 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Verify PATCH IPv6 address at subinterface level ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface" - expected_get_json = "{\"openconfig-interfaces:subinterface\": [{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv6\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"family\":\"ipv6\",\"ip\":\"a::e\",\"prefix-length\":64}}]},\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}" + expected_get_json = "{\"openconfig-interfaces:subinterface\": [{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv6\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"ip\":\"a::e\",\"prefix-length\":64}}]},\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}" t.Run("Test Get/Verify Patch IPv6 address at subinterface", processGetRequest(url, nil, expected_get_json, false)) time.Sleep(1 * time.Second) @@ -274,7 +277,7 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Verify PATCH IPv6 address at addresses level ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/addresses" - expected_get_json = "{\"openconfig-if-ip:addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"family\":\"ipv6\",\"ip\":\"a::e\",\"prefix-length\":64}}]}}" + expected_get_json = "{\"openconfig-if-ip:addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"ip\":\"a::e\",\"prefix-length\":64}}]}}" t.Run("Test Get/Verify Patch IPv6 address at subinterfaces addresses", processGetRequest(url, nil, expected_get_json, false)) time.Sleep(1 * time.Second) @@ -308,8 +311,7 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Verify Get at interfaces/interface[name=Ethernet0] ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]" - expected_get_json = "{\"openconfig-interfaces:interface\":[{\"config\":{\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"openconfig-if-ethernet:ethernet\":{\"config\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"},\"state\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"}},\"name\":\"Ethernet0\",\"state\":{\"admin-status\":\"UP\",\"description\":\"\",\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"subinterfaces\":{\"subinterface\":[{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv6\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"family\":\"ipv6\",\"ip\":\"a::e\",\"prefix-length\":64}}]},\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}}]}" - + expected_get_json = "{\"openconfig-interfaces:interface\":[{\"config\":{\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"openconfig-if-ethernet:ethernet\":{\"config\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"},\"state\":{\"auto-negotiate\":false,\"port-speed\":\"openconfig-if-ethernet:SPEED_10GB\"}},\"name\":\"Ethernet0\",\"state\":{\"admin-status\":\"UP\",\"description\":\"\",\"enabled\":true,\"mtu\":9100,\"name\":\"Ethernet0\"},\"subinterfaces\":{\"subinterface\":[{\"config\":{\"index\":0},\"index\":0,\"openconfig-if-ip:ipv6\":{\"addresses\":{\"address\":[{\"config\":{\"ip\":\"a::e\",\"prefix-length\":64},\"ip\":\"a::e\",\"state\":{\"ip\":\"a::e\",\"prefix-length\":64}}]},\"config\":{\"enabled\":false}},\"state\":{\"index\":0}}]}}]}" t.Run("Test Get at interfaces/interface[name=Ethernet0]", processGetRequest(url, nil, expected_get_json, false)) time.Sleep(1 * time.Second) @@ -317,8 +319,8 @@ func Test_openconfig_subintf(t *testing.T) { t.Log("\n\n--- Negative test: Delete IPv6 config container ---") url = "/openconfig-interfaces:interfaces/interface[name=Ethernet0]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv6/config" - err_str = "Delete not allowed at this container" - expected_err_2 = tlerr.NotSupportedError{Format: err_str} + err_str := "Delete not allowed at this container" + expected_err_2 := tlerr.NotSupportedError{Format: err_str} time.Sleep(1 * time.Second) t.Run("Test Delete IPv6 config", processDeleteRequest(url, true, expected_err_2)) time.Sleep(1 * time.Second) From 4cbde324242191cc48f11718fd7c1ce88ab516b0 Mon Sep 17 00:00:00 2001 From: Satoru-Shinohara Date: Thu, 22 Feb 2024 18:28:14 -0500 Subject: [PATCH 12/13] Adding fixes based on review. Adding go.mod and go.sum files for translib.test --- go.mod | 3 +- go.sum | 26 ++++ .../openconfig-interfaces-annot.yang | 2 - .../openconfig-interfaces-deviation.yang | 121 +++++++++++++- .../extensions/openconfig-interfaces-ext.yang | 147 ------------------ models/yang/openconfig-if-ethernet.yang | 80 +--------- translib/transformer/xfmr_intf.go | 64 -------- 7 files changed, 152 insertions(+), 291 deletions(-) delete mode 100644 models/yang/extensions/openconfig-interfaces-ext.yang diff --git a/go.mod b/go.mod index f2dbd9a18..b47587698 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,9 @@ require ( github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3 // indirect github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f github.com/pkg/profile v1.7.0 - golang.org/x/text v0.3.0 + golang.org/x/text v0.3.3 google.golang.org/grpc v1.28.0 + inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a ) go 1.13 diff --git a/go.sum b/go.sum index 9cbf4b739..aec58acaf 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -93,13 +94,21 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE= +go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= +go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= +go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 h1:WJhcL4p+YeDxmZWg141nRm7XC8IDmhz7lk5GpadO1Sg= +go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -107,14 +116,18 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= @@ -123,15 +136,25 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -163,3 +186,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +inet.af v0.0.0-20181218191229-53da77bc832c h1:U3RoiyEF5b3Y1SVL6NNvpkgqUz2qS3a0OJh9kpSCN04= +inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a h1:1XCVEdxrvL6c0TGOhecLuB7U9zYNdxZEjvOqJreKZiM= +inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a/go.mod h1:e83i32mAQOW1LAqEIweALsuK2Uw4mhQadA5r7b0Wobo= diff --git a/models/yang/annotations/openconfig-interfaces-annot.yang b/models/yang/annotations/openconfig-interfaces-annot.yang index d3124f0f6..64fb448f7 100644 --- a/models/yang/annotations/openconfig-interfaces-annot.yang +++ b/models/yang/annotations/openconfig-interfaces-annot.yang @@ -19,7 +19,6 @@ module openconfig-interfaces-annot { deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config { deviate add { sonic-ext:subtree-transformer "intf_eth_port_config_xfmr"; - sonic-ext:path-transformer "intf_eth_port_config_path_xfmr"; } } @@ -95,7 +94,6 @@ module openconfig-interfaces-annot { sonic-ext:table-transformer "intf_subintfs_table_xfmr"; sonic-ext:virtual-table "true"; sonic-ext:key-transformer "intf_subintfs_xfmr"; - sonic-ext:path-transformer "intf_ip_path_xfmr"; } } diff --git a/models/yang/extensions/openconfig-interfaces-deviation.yang b/models/yang/extensions/openconfig-interfaces-deviation.yang index e3fd326b7..fcc9eddce 100644 --- a/models/yang/extensions/openconfig-interfaces-deviation.yang +++ b/models/yang/extensions/openconfig-interfaces-deviation.yang @@ -12,6 +12,9 @@ module openconfig-interfaces-deviation { import openconfig-extensions { prefix oc-ext; } import openconfig-if-ip {prefix oc-ip; } import openconfig-vlan { prefix oc-vlan; } + import openconfig-if-ethernet {prefix oc-eth; } + import openconfig-if-aggregate {prefix oc-lag; } + import openconfig-if-tunnel {prefix oc-tun; } organization "SONiC"; @@ -22,14 +25,62 @@ module openconfig-interfaces-deviation { description "This module describes a YANG model for openconfig-interfaces deviations."; - oc-ext:openconfig-version "0.2.7"; + oc-ext:openconfig-version "0.1.0"; revision "2024-01-19" { description - "Add Yang deviations for unsupported subinterfaces."; - reference "0.2.7"; + "Add Yang deviations for unsupported interface attributes."; + reference "0.1.0"; } + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-intf:loopback-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-vlan:tpid { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-intf:type { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:loopback-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:oper-status { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:last-change { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:counters { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:type { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:ifindex { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:logical { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-vlan:tpid { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:hold-time { + deviate not-supported; + } + deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-intf:state/oc-intf:ifindex { deviate not-supported; } @@ -131,5 +182,69 @@ module openconfig-interfaces-deviation { deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:subinterfaces/oc-intf:subinterface/oc-ip:ipv6/oc-ip:state { deviate not-supported; } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-eth:mac-address { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-eth:duplex-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-eth:enable-flow-control { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-lag:aggregate-id { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:mac-address { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:duplex-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:enable-flow-control { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:counters { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-lag:aggregate-id { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:hw-mac-address { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:negotiated-duplex-mode { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:negotiated-port-speed { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-vlan:switched-vlan { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-tun:tunnel { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-lag:aggregation { + deviate not-supported; + } + + deviation /oc-intf:interfaces/oc-intf:interface/oc-vlan:routed-vlan { + deviate not-supported; + } } diff --git a/models/yang/extensions/openconfig-interfaces-ext.yang b/models/yang/extensions/openconfig-interfaces-ext.yang deleted file mode 100644 index 73b70e46a..000000000 --- a/models/yang/extensions/openconfig-interfaces-ext.yang +++ /dev/null @@ -1,147 +0,0 @@ -module openconfig-interfaces-ext { - - yang-version "1.1"; - - // namespace - namespace "http://openconfig.net/yang/interfaces/extension"; - - prefix "oc-intf-ext"; - - import openconfig-extensions { prefix oc-ext; } - import openconfig-interfaces { prefix oc-intf; } - import openconfig-vlan { prefix oc-vlan; } - import openconfig-if-ethernet {prefix oc-eth; } - import openconfig-if-aggregate {prefix oc-lag; } - import openconfig-if-tunnel {prefix oc-tun; } - - - organization "SONiC"; - - contact - "SONiC"; - - description - "This module contains collection of yang definitions for extensions to - openconfig-interfaces yang"; - - oc-ext:openconfig-version "0.1.0"; - - revision 2024-01-18 { - description - "Initial version."; - reference "0.1.0"; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-intf:loopback-mode { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-vlan:tpid { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:config/oc-intf:type { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:loopback-mode { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:oper-status { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:last-change { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:counters { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:type { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:ifindex { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-intf:logical { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:state/oc-vlan:tpid { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-intf:hold-time { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-eth:mac-address { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-eth:duplex-mode { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-eth:enable-flow-control { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:config/oc-lag:aggregate-id { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:mac-address { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:duplex-mode { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:enable-flow-control { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:counters { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-lag:aggregate-id { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:hw-mac-address { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:negotiated-duplex-mode { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-eth:state/oc-eth:negotiated-port-speed { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-eth:ethernet/oc-vlan:switched-vlan { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-tun:tunnel { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-lag:aggregation { - deviate not-supported; - } - - deviation /oc-intf:interfaces/oc-intf:interface/oc-vlan:routed-vlan { - deviate not-supported; - } - -} \ No newline at end of file diff --git a/models/yang/openconfig-if-ethernet.yang b/models/yang/openconfig-if-ethernet.yang index 4e15bd28a..a852fc83b 100644 --- a/models/yang/openconfig-if-ethernet.yang +++ b/models/yang/openconfig-if-ethernet.yang @@ -24,82 +24,14 @@ module openconfig-if-ethernet { "Model for managing Ethernet interfaces -- augments the OpenConfig model for interface configuration and state."; - oc-ext:openconfig-version "2.13.0"; + oc-ext:openconfig-version "2.7.0"; - revision "2023-03-10" { + revision "2024-02-22" { description - "Allow Ethernet configuration parameters to be - used for aggregate (LAG) interfaces."; - reference "2.13.0"; - } - - revision "2022-04-20" { - description - "Remove unused import"; - reference "2.12.2"; - } - - revision "2021-07-20" { - description - "Fix typo in hardware MAC address description."; - reference "2.12.1"; - } - - revision "2021-07-07" { - description - "Add support for configuring fec-mode per interface."; - reference "2.12.0"; - } - - revision "2021-06-16" { - description - "Remove trailing whitespace."; - reference "2.11.1"; - } - - revision "2021-06-09" { - description - "Add support for standalone link training."; - reference "2.11.0"; - } - - revision "2021-05-17" { - description - "Add ethernet counters: in-carrier-errors, - in-interrupted-tx, in-late-collision, in-mac-errors-rx, - in-single-collision, in-symbol-error and out-mac-errors-tx"; - reference "2.10.0"; - } - - revision "2021-03-30" { - description - "Add counter for drops due to oversized frames."; - reference "2.9.0"; - } - - revision "2020-05-06" { - description - "Minor formatting fix."; - reference "2.8.1"; - } - - revision "2020-05-06" { - description - "Add 200G, 400G, 600G and 800G Ethernet speeds."; - reference "2.8.0"; - } - - revision "2020-05-05" { - description - "Fix when statement checks to use rw paths when - from a rw context."; - reference "2.7.3"; - } - - revision "2019-04-16" { - description - "Update import prefix for iana-if-type module"; - reference "2.7.2"; + "Add 200G, 400G, 600G, and 800G Ethernet Speeds. + Minor formatting fix and fixed a typo in + hardware MAC addr description."; + reference "2.7.0"; } revision "2018-11-21" { diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go index 192d739c7..d878431b3 100644 --- a/translib/transformer/xfmr_intf.go +++ b/translib/transformer/xfmr_intf.go @@ -47,7 +47,6 @@ func init() { XlateFuncBind("DbToYang_intf_enabled_xfmr", DbToYang_intf_enabled_xfmr) XlateFuncBind("YangToDb_intf_eth_port_config_xfmr", YangToDb_intf_eth_port_config_xfmr) XlateFuncBind("DbToYang_intf_eth_port_config_xfmr", DbToYang_intf_eth_port_config_xfmr) - XlateFuncBind("DbToYangPath_intf_eth_port_config_path_xfmr", DbToYangPath_intf_eth_port_config_path_xfmr) XlateFuncBind("DbToYang_intf_eth_auto_neg_xfmr", DbToYang_intf_eth_auto_neg_xfmr) XlateFuncBind("DbToYang_intf_eth_port_speed_xfmr", DbToYang_intf_eth_port_speed_xfmr) @@ -62,7 +61,6 @@ func init() { XlateFuncBind("intf_subintfs_table_xfmr", intf_subintfs_table_xfmr) XlateFuncBind("YangToDb_subif_index_xfmr", YangToDb_subif_index_xfmr) XlateFuncBind("DbToYang_subif_index_xfmr", DbToYang_subif_index_xfmr) - XlateFuncBind("DbToYangPath_intf_ip_path_xfmr", DbToYangPath_intf_ip_path_xfmr) XlateFuncBind("Subscribe_intf_ip_addr_xfmr", Subscribe_intf_ip_addr_xfmr) XlateFuncBind("YangToDb_subintf_ipv6_tbl_key_xfmr", YangToDb_subintf_ipv6_tbl_key_xfmr) @@ -763,27 +761,6 @@ var DbToYang_intf_eth_port_config_xfmr SubTreeXfmrDbToYang = func(inParams XfmrP return err } -var DbToYangPath_intf_eth_port_config_path_xfmr PathXfmrDbToYangFunc = func(params XfmrDbToYgPathParams) error { - log.Info("DbToYangPath_intf_eth_port_config_path_xfmr: params: ", params) - - intfRoot := "/openconfig-interfaces:interfaces/interface" - if params.tblName != "PORT" { - log.Info("DbToYangPath_intf_eth_port_config_path_xfmr: from wrong table: ", params.tblName) - return nil - } - - if (params.tblName == "PORT") && (len(params.tblKeyComp) > 0) { - params.ygPathKeys[intfRoot+"/name"] = params.tblKeyComp[0] - } else { - log.Info("DbToYangPath_intf_eth_port_config_path_xfmr, wrong param: tbl ", params.tblName, " key ", params.tblKeyComp) - return nil - } - - log.Info("DbToYangPath_intf_eth_port_config_path_xfmr: params.ygPathkeys: ", params.ygPathKeys) - - return nil -} - var DbToYang_intf_eth_auto_neg_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map[string]interface{}, error) { var err error result := make(map[string]interface{}) @@ -1040,47 +1017,6 @@ var DbToYang_subif_index_xfmr FieldXfmrDbtoYang = func(inParams XfmrParams) (map return res_map, nil } -var DbToYangPath_intf_ip_path_xfmr PathXfmrDbToYangFunc = func(params XfmrDbToYgPathParams) error { - ifRoot := "/openconfig-interfaces:interfaces/interface" - subIf := ifRoot + "/subinterfaces/subinterface" - dbKey := "" - - log.Info("DbToYangPath_intf_ip_path_xfmr: params: ", params) - - uiName := ¶ms.tblKeyComp[0] - ifParts := strings.Split(*uiName, ".") - - params.ygPathKeys[ifRoot+"/name"] = ifParts[0] - - if params.tblName == "INTERFACE" || params.tblName == "INTF_TABLE" { - - addrPath := "/openconfig-if-ip:ipv4/addresses/address/ip" - - /* For APPL_DB IPv6 case, addr is split [fe80 56bf 64ff feba 3bc0/64] instead of - [fe80::56bf:64ff:feba:3bc0/64] - Handle this case - */ - dbKey = strings.Join(params.tblKeyComp[1:], ":") - - if len(params.tblKeyComp) > 2 || strings.Contains(dbKey, ":") { - addrPath = "/openconfig-if-ip:ipv6/addresses/address/ip" - } - - ipKey := strings.Split(dbKey, "/") - - if len(ifParts) > 1 { - params.ygPathKeys[subIf+"/index"] = ifParts[1] - } else { - params.ygPathKeys[subIf+"/index"] = "0" - } - params.ygPathKeys[subIf+addrPath] = ipKey[0] - - } - - log.Infof("DbToYangPath_intf_ip_path_xfmr: tblName:%v dbKey:[%v] params.ygPathKeys: %v", params.tblName, dbKey, params.ygPathKeys) - return nil -} - /* Get interface to IP mapping for all interfaces in the given table */ func getCachedAllIntfIpMap(dbCl *db.DB, tblName string, ipv4 bool, ipv6 bool, ip string, tblPattern *db.Table) (map[string]map[string]db.Value, error) { var err error From e264cf633fd9036ed6d3329b1d7adcf2babcdf3f Mon Sep 17 00:00:00 2001 From: Satoru-Shinohara Date: Wed, 28 Feb 2024 17:44:35 -0500 Subject: [PATCH 13/13] Address additional review comments regarding port-speed and switch case formatting --- translib/transformer/xfmr_intf.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go index d878431b3..d86ab918f 100644 --- a/translib/transformer/xfmr_intf.go +++ b/translib/transformer/xfmr_intf.go @@ -126,6 +126,7 @@ var intfOCToSpeedMap = map[ocbinds.E_OpenconfigIfEthernet_ETHERNET_SPEED]string{ ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_100GB: "100000", ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_200GB: "200000", ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_400GB: "400000", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_800GB: "800000", } type E_InterfaceType int64 @@ -159,17 +160,13 @@ func getIntfsRoot(s *ygot.GoStruct) *ocbinds.OpenconfigInterfaces_Interfaces { func getPortTableNameByDBId(intftbl IntfTblData, curDb db.DBNum) (string, error) { - var tblName string + tblName := intftbl.cfgDb.portTN switch curDb { - case db.ConfigDB: - tblName = intftbl.cfgDb.portTN case db.ApplDB: tblName = intftbl.appDb.portTN case db.StateDB: tblName = intftbl.stateDb.portTN - default: - tblName = intftbl.cfgDb.portTN } return tblName, nil