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/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 new file mode 100644 index 000000000..64fb448f7 --- /dev/null +++ b/models/yang/annotations/openconfig-interfaces-annot.yang @@ -0,0 +1,161 @@ +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/oc-intf:interface/oc-eth:ethernet/oc-eth:config { + deviate add { + sonic-ext:subtree-transformer "intf_eth_port_config_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-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-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 { + deviate add { + sonic-ext:db-name "APPL_DB"; + } + } + + 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-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 { + deviate add { + sonic-ext:pre-transformer "intf_pre_xfmr"; + sonic-ext:post-transformer "intf_post_xfmr"; + } + } + + 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"; + } + } + + 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-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..fcc9eddce --- /dev/null +++ b/models/yang/extensions/openconfig-interfaces-deviation.yang @@ -0,0 +1,250 @@ +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; } + 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 describes a YANG model for openconfig-interfaces deviations."; + + oc-ext:openconfig-version "0.1.0"; + + revision "2024-01-19" { + description + "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; + } + + 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; + } + + 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/openconfig-if-ethernet.yang b/models/yang/openconfig-if-ethernet.yang index e917bba4d..a852fc83b 100644 --- a/models/yang/openconfig-if-ethernet.yang +++ b/models/yang/openconfig-if-ethernet.yang @@ -24,7 +24,15 @@ 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.7.0"; + + revision "2024-02-22" { + description + "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" { description @@ -146,6 +154,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 +377,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 +410,7 @@ module openconfig-if-ethernet { description "Ethernet interface counters"; uses ethernet-interface-state-counters; - } - } // data definition statements diff --git a/models/yang/openconfig-if-ip.yang b/models/yang/openconfig-if-ip.yang index df89662f8..8680d2dc8 100644 --- a/models/yang/openconfig-if-ip.yang +++ b/models/yang/openconfig-if-ip.yang @@ -390,6 +390,7 @@ module openconfig-if-ip { description "The length of the subnet prefix."; } + } grouping ipv4-neighbor-config { 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/interfaces_openconfig_test.go b/translib/transformer/interfaces_openconfig_test.go new file mode 100644 index 000000000..cc343ff45 --- /dev/null +++ b/translib/transformer/interfaces_openconfig_test.go @@ -0,0 +1,564 @@ +//////////////////////////////////////////////////////////////////////////////// +// // +// 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_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\": \"\"}" + 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\": \"\", \"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\":9100,\"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\": \"\", \"enabled\": true, \"mtu\": 9100, \"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) + +} + +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 ++++++++++++") + 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\":{\"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\":{\"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\":{ \"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\":{\"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 ++++++++++++") +} + +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 ---") + 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\":{\"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\":{\"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\":{\"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\":{\"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 ++++++++++++") +} diff --git a/translib/transformer/xfmr_intf.go b/translib/transformer/xfmr_intf.go new file mode 100644 index 000000000..d86ab918f --- /dev/null +++ b/translib/transformer/xfmr_intf.go @@ -0,0 +1,2152 @@ +////////////////////////////////////////////////////////////////////////// +// +// 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" + "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("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("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) + + 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("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" + PORT_SPEED = "speed" + PORT_AUTONEG = "autoneg" + DEFAULT_MTU = "9100" +) + +const ( + PIPE = "|" + COLON = ":" + ETHERNET = "Eth" +) + +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}, + }, +} + +var dbIdToTblMap = map[db.DBNum][]string{ + db.ConfigDB: {"PORT"}, + db.ApplDB: {"PORT_TABLE"}, + db.StateDB: {"PORT_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", + ocbinds.OpenconfigIfEthernet_ETHERNET_SPEED_SPEED_800GB: "800000", +} + +type E_InterfaceType int64 + +const ( + IntfTypeUnset E_InterfaceType = 0 + IntfTypeEthernet E_InterfaceType = 1 +) + +type E_InterfaceSubType int64 + +const ( + IntfSubTypeUnset E_InterfaceSubType = 0 +) + +func getIntfTypeByName(name string) (E_InterfaceType, E_InterfaceSubType, error) { + + var err error + 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) { + + tblName := intftbl.cfgDb.portTN + + switch curDb { + case db.ApplDB: + tblName = intftbl.appDb.portTN + case db.StateDB: + tblName = intftbl.stateDb.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 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") { + // 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) + } + } + } + } + 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 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 + } + } + + 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") { + tblList = append(tblList, intTbl.cfgDb.portTN) + + } 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 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") { + 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 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") + } + 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) + intfsObj := getIntfsRoot(inParams.ygRoot) + if intfsObj == nil || len(intfsObj.Interface) < 1 { + 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") + } + + 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 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 inParams.oper == DELETE { + log.Infof("Updating the Interface: %s with default MTU", ifName) + /* 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) + + 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") + } + + 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, 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 + 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 + } + + intfsObj := getIntfsRoot(inParams.ygRoot) + intfObj := intfsObj.Interface[uriIfName] + + // 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 + 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") { + 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 + 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 == IntfTypeEthernet { + intTbl := IntfTypeTblMap[intfType] + autoNeg := intfObj.Ethernet.Config.AutoNegotiate + var enStr string + if *autoNeg { + enStr = "on" + } 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 + } + 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 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 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 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") + } + + 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 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 +} + +var intf_subintfs_table_xfmr TableXfmrFunc = func(inParams XfmrParams) ([]string, error) { + var tblList []string + + pathInfo := NewPathInfo(inParams.uri) + idx := pathInfo.Var("index") + + 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") + } + } + 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") + } + 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") + } + + 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 +} + +/* 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 { + + 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 + + if entry == nil { + 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") + i32 := uint32(0) + 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() + if isState { + v4Address.State.Ip = ipStr + v4Address.State.PrefixLength = prfxLen + } 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() + if isState { + v6Address.State.Ip = ipStr + v6Address.State.PrefixLength = prfxLen + } 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 := [1]E_InterfaceType{IntfTypeEthernet} + + // 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) + + 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) + + 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) + + 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), "|") + m["family"] = "IPv4" + + 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) + + /* 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), "|") + + m["family"] = "IPv6" + + 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)) + } + + //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) + } + } + } + } + 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 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"] + /* Note: Unbinding shouldn't happen if VRF config is associated with interface. + Hence, we check for map length and only if NULL value is present */ + if len(intfEntryMap) == 1 && nullValPresent { + 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 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) + // 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. +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) + } + inst_key = ifName + 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") + + intfType, _, ierr := getIntfTypeByName(ifUIName) + if ierr != nil || intfType == IntfTypeUnset { + 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 { + 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 + 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) + + 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..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"