diff --git a/go.mod b/go.mod index 565a95e5..a139a31c 100644 --- a/go.mod +++ b/go.mod @@ -10,12 +10,14 @@ require ( github.com/networkservicemesh/api v1.0.1-0.20210907194827-9a36433d7d6e github.com/networkservicemesh/sdk v0.5.1-0.20211014092525-f264fec6da05 github.com/networkservicemesh/sdk-kernel v0.0.0-20211014092923-08c76a5ebb5c + github.com/networkservicemesh/sdk-sriov v0.0.0-20210924085919-868bbc152fb4 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.0 github.com/thanhpk/randstr v1.0.4 github.com/vishvananda/netlink v1.1.0 + golang.org/x/tools v0.1.7 // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b google.golang.org/grpc v1.35.0 google.golang.org/protobuf v1.25.0 - gopkg.in/yaml.v2 v2.2.4 // indirect ) + diff --git a/go.sum b/go.sum index 98f46308..256ad6ff 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/edwarnicke/exechelper v1.0.2/go.mod h1:/T271jtNX/ND4De6pa2aRy2+8sNtyCDB1A2pp4M+fUs= github.com/edwarnicke/govpp v0.0.0-20210928024809-7b7ae743b62d h1:KvhkLWa50BIeFWBTEEQJnH69BLc7VfRQWISbN3jCgX4= github.com/edwarnicke/govpp v0.0.0-20210928024809-7b7ae743b62d/go.mod h1:kHDnxA+SSNFeMEHz7xvhub1zvx4mOTRlWWRCay2n5NM= +github.com/edwarnicke/grpcfd v0.1.0/go.mod h1:rHihB9YvNMixz8rS+ZbwosI2kj65VLkeyYAI2M+/cGA= github.com/edwarnicke/grpcfd v0.1.1 h1:ej5J1V7iSRa4RF1OIXfaVKsEWCMLIGiNECLgh7juxBA= github.com/edwarnicke/grpcfd v0.1.1/go.mod h1:rHihB9YvNMixz8rS+ZbwosI2kj65VLkeyYAI2M+/cGA= github.com/edwarnicke/serialize v0.0.0-20200705214914-ebc43080eecf/go.mod h1:XvbCO/QGsl3X8RzjBMoRpkm54FIAZH5ChK2j+aox7pw= @@ -83,8 +84,9 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v0.0.0-20181024020800-521ea7b17d02/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= @@ -138,12 +140,14 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/stan.go v0.6.0/go.mod h1:eIcD5bi3pqbHT/xIIvXMwvzXYElgouBvaVRftaE+eac= -github.com/networkservicemesh/api v1.0.1-0.20210907194827-9a36433d7d6e h1:PO6tDo/bGLJqz1qiqCecht/HqMWCKunAds2U9Hvc0yM= -github.com/networkservicemesh/api v1.0.1-0.20210907194827-9a36433d7d6e/go.mod h1:B6meq/SWjWR6bGXZdXPfbOeaBK+T1JayLdtEJQCsXKU= +github.com/networkservicemesh/sdk v0.5.1-0.20210923121729-a96ead921c0e/go.mod h1:eISPu+ySJJ46kg03ZTi/xmpNSU+K4cImwq++ZbDV4F4= github.com/networkservicemesh/sdk v0.5.1-0.20211014092525-f264fec6da05 h1:oKButffgafeq8d1X/0DyvGETzLApGpu3c+xjrgefOwk= github.com/networkservicemesh/sdk v0.5.1-0.20211014092525-f264fec6da05/go.mod h1:j/XeYOfyRzuQBV4llU+qTOhN7aZSMO6scfHI9adWdzc= +github.com/networkservicemesh/sdk-kernel v0.0.0-20210923122046-7d822150f22a/go.mod h1:qDNhKWmvnMvCs19+YF+4tgYwG0+fN2uNW95jr8VqzjI= github.com/networkservicemesh/sdk-kernel v0.0.0-20211014092923-08c76a5ebb5c h1:Qh/zpbpupujQ7WtbbE33cIzKaV3JLrie9TsGjslFsgo= github.com/networkservicemesh/sdk-kernel v0.0.0-20211014092923-08c76a5ebb5c/go.mod h1:3bouhA9gAe0mMpnohxDD7xYGkNhiEEQQgBywT/iwQtM= +github.com/networkservicemesh/sdk-sriov v0.0.0-20210924085919-868bbc152fb4 h1:NA8YzBX8W28MMDYMmPk99tKf5ijD3zYE0DYfAKOZxEc= +github.com/networkservicemesh/sdk-sriov v0.0.0-20210924085919-868bbc152fb4/go.mod h1:agnfxvuC9k/LTBT7azseDToGC5GKvJbAwohBy8f40i4= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -206,6 +210,7 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1 github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b h1:vVRagRXf67ESqAb72hG2C/ZwI8NtJF2u2V76EsuOHGY= github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b/go.mod h1:HptNXiXVDcJjXe9SqMd0v2FsL9f8dz4GnXgltU6q/co= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zeebo/errs v1.2.2/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= @@ -229,8 +234,10 @@ golang.org/x/lint v0.0.0-20181023182221-1baf3a9d7d67/go.mod h1:UVdnD1Gm6xHRNCYTk 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/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/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= @@ -246,8 +253,9 @@ golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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= @@ -276,8 +284,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644 h1:CA1DEQ4NdKphKeL70tvsWNdT5oFh1lOjihRcEDROi0I= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -296,8 +305,10 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 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= @@ -317,8 +328,9 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7 h1:1N7l1PuXZwEK7OhHdmKQROOM75PnUjABGwvVRbLBgFk= +google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -336,6 +348,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -347,8 +360,8 @@ gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/networkservice/chains/xconnectns/server.go b/pkg/networkservice/chains/xconnectns/server.go index b147fd7a..bd69d4be 100644 --- a/pkg/networkservice/chains/xconnectns/server.go +++ b/pkg/networkservice/chains/xconnectns/server.go @@ -24,6 +24,7 @@ import ( "context" "net" "net/url" + "sync" "git.fd.io/govpp.git/api" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/client" @@ -31,6 +32,7 @@ import ( "google.golang.org/grpc" "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/networkservicemesh/sdk-kernel/pkg/kernel/networkservice/connectioncontextkernel" "github.com/networkservicemesh/sdk/pkg/networkservice/chains/endpoint" "github.com/networkservicemesh/sdk/pkg/networkservice/common/clienturl" "github.com/networkservicemesh/sdk/pkg/networkservice/common/mechanisms" @@ -39,11 +41,11 @@ import ( "github.com/networkservicemesh/sdk/pkg/networkservice/common/mechanismtranslation" "github.com/networkservicemesh/sdk/pkg/tools/token" - "github.com/networkservicemesh/sdk-kernel/pkg/kernel/networkservice/connectioncontextkernel" - "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/connectioncontext/mtu" "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/kernel" "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/memif" + "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan" + "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/pciaddresspool" "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vxlan" "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/wireguard" "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/pinhole" @@ -64,8 +66,9 @@ type xconnectNSServer struct { } // NewServer - returns an implementation of the xconnectns network service -func NewServer(ctx context.Context, name string, authzServer networkservice.NetworkServiceServer, tokenGenerator token.GeneratorFunc, clientURL *url.URL, vppConn Connection, tunnelIP net.IP, tunnelPort uint16, clientDialOptions ...grpc.DialOption) endpoint.Endpoint { +func NewServer(ctx context.Context, name string, authzServer networkservice.NetworkServiceServer, tokenGenerator token.GeneratorFunc, clientURL *url.URL, vppConn Connection, tunnelIP net.IP, tunnelPort uint16, resourcePool pciaddresspool.PCIAddressPool, clientDialOptions ...grpc.DialOption) endpoint.Endpoint { rv := &xconnectNSServer{} + resourceLock := &sync.Mutex{} additionalFunctionality := []networkservice.NetworkServiceServer{ recvfd.NewServer(), sendfd.NewServer(), @@ -101,6 +104,7 @@ func NewServer(ctx context.Context, name string, authzServer networkservice.Netw kernel.NewClient(vppConn), vxlan.NewClient(vppConn, tunnelIP, vxlan.WithVniPort(tunnelPort)), wireguard.NewClient(vppConn, tunnelIP), + vlan.NewClient(vppConn, resourceLock, resourcePool), pinhole.NewClient(vppConn), recvfd.NewClient(), sendfd.NewClient()), diff --git a/pkg/networkservice/mechanisms/vlan/client.go b/pkg/networkservice/mechanisms/vlan/client.go new file mode 100644 index 00000000..be765207 --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/client.go @@ -0,0 +1,189 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 vlan + +import ( + "context" + "io" + "sync" + "time" + + "git.fd.io/govpp.git/api" + interfaces "github.com/edwarnicke/govpp/binapi/interface" + "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/cls" + vlanmech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/vlan" + "github.com/networkservicemesh/api/pkg/api/networkservice/payload" + kernellink "github.com/networkservicemesh/sdk-kernel/pkg/kernel" + "github.com/networkservicemesh/sdk-kernel/pkg/kernel/tools/nshandle" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/chain" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/tools/log" + "github.com/networkservicemesh/sdk/pkg/tools/postpone" + + "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/l2vtr" + "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/linkinit" + "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/pciaddresspool" + "github.com/networkservicemesh/sdk-vpp/pkg/tools/ifindex" +) + +type vlanClient struct { + vppConn api.Connection +} + +// NewClient returns a VLAN client chain element +func NewClient(vppConn api.Connection, resourceLock sync.Locker, resourcePool pciaddresspool.PCIAddressPool) networkservice.NetworkServiceClient { + return chain.NewNetworkServiceClient( + l2vtr.NewClient(vppConn), + &vlanClient{vppConn: vppConn}, + linkinit.NewClient(vppConn), + pciaddresspool.NewClient(resourceLock, resourcePool), + ) +} + +func (v *vlanClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { + if request.GetConnection().GetPayload() != payload.Ethernet { + return next.Client(ctx).Request(ctx, request, opts...) + } + + mechanism := &networkservice.Mechanism{ + Cls: cls.REMOTE, + Type: vlanmech.MECHANISM, + Parameters: make(map[string]string), + } + request.MechanismPreferences = append(request.MechanismPreferences, mechanism) + + postponeCtxFunc := postpone.ContextWithValues(ctx) + + conn, err := next.Client(ctx).Request(ctx, request, opts...) + if err != nil { + return nil, err + } + + if err := addSubIf(ctx, conn, v.vppConn); err != nil { + closeCtx, cancelClose := postponeCtxFunc() + defer cancelClose() + + if _, closeErr := v.Close(closeCtx, conn, opts...); closeErr != nil { + err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error()) + } + + return nil, err + } + + return conn, nil +} + +func (v *vlanClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { + if conn.GetPayload() != payload.Ethernet { + return next.Client(ctx).Close(ctx, conn, opts...) + } + _ = delSubIf(ctx, conn, v.vppConn) + return next.Client(ctx).Close(ctx, conn, opts...) +} + +func addSubIf(ctx context.Context, conn *networkservice.Connection, vppConn api.Connection) error { + if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { + _, ok := ifindex.Load(ctx, true) + if ok { + return nil + } + now := time.Now() + pciAddressInfo, ok := pciaddresspool.Load(ctx) + if !ok { + return errors.Errorf("no link found") + } + hostNetNS, err := nshandle.Current() + if err != nil { + return err + } + defer func() { _ = hostNetNS.Close() }() + kernelLink, err := kernellink.FindHostDevice(pciAddressInfo.GetPCIAddress(), "", hostNetNS) + if err != nil { + return err + } + hostIFName := kernelLink.GetName() + + client, err := interfaces.NewServiceClient(vppConn).SwInterfaceDump(ctx, &interfaces.SwInterfaceDump{ + NameFilterValid: true, + NameFilter: hostIFName, + }) + if err != nil { + return errors.Wrapf(err, "error attempting to get interface dump client to set vlan subinterface on %q", hostIFName) + } + log.FromContext(ctx). + WithField("duration", time.Since(now)). + WithField("HostInterfaceName", hostIFName). + WithField("vppapi", "SwInterfaceDump").Debug("completed") + + for { + details, err := client.Recv() + if err == io.EOF { + break + } + if err != nil { + return errors.Wrapf(err, "error attempting to get interface details to set vlan subinterface on %q", hostIFName) + } + now = time.Now() + swIfIndex := details.SwIfIndex + vlanID := mechanism.GetVlanID() + vlanSubif := &interfaces.CreateVlanSubif{ + SwIfIndex: swIfIndex, + VlanID: vlanID, + } + + rsp, err := interfaces.NewServiceClient(vppConn).CreateVlanSubif(ctx, vlanSubif) + if err != nil { + return errors.WithStack(err) + } + log.FromContext(ctx). + WithField("duration", time.Since(now)). + WithField("HostInterfaceIndex", swIfIndex). + WithField("VlanID", vlanID). + WithField("vppapi", "CreateVlanSubIf").Debug("completed") + + ifindex.Store(ctx, true, rsp.SwIfIndex) + } + } + return nil +} +func delSubIf(ctx context.Context, conn *networkservice.Connection, vppConn api.Connection) error { + if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { + swIfIndex, ok := ifindex.Load(ctx, true) + if !ok { + return nil + } + now := time.Now() + vlanSubif := &interfaces.DeleteSubif{ + SwIfIndex: swIfIndex, + } + _, err := interfaces.NewServiceClient(vppConn).DeleteSubif(ctx, vlanSubif) + if err != nil { + return errors.WithStack(err) + } + log.FromContext(ctx). + WithField("duration", time.Since(now)). + WithField("HostInterfaceIndex", swIfIndex). + WithField("vppapi", "DeleteSubif").Debug("completed") + ifindex.Delete(ctx, true) + } + return nil +} diff --git a/pkg/networkservice/mechanisms/vlan/doc.go b/pkg/networkservice/mechanisms/vlan/doc.go new file mode 100644 index 00000000..4a101d38 --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/doc.go @@ -0,0 +1,18 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 vlan provides chain elements for implementing the vlan mechanism +package vlan diff --git a/pkg/networkservice/mechanisms/vlan/l2vtr/client.go b/pkg/networkservice/mechanisms/vlan/l2vtr/client.go new file mode 100644 index 00000000..c36664a4 --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/l2vtr/client.go @@ -0,0 +1,121 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 l2vtr + +import ( + "context" + "time" + + "git.fd.io/govpp.git/api" + "github.com/edwarnicke/govpp/binapi/l2" + "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + vlanmech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/vlan" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/tools/log" + "github.com/networkservicemesh/sdk/pkg/tools/postpone" + + "github.com/networkservicemesh/sdk-vpp/pkg/tools/ifindex" +) + +type l2vtrClient struct { + vppConn api.Connection +} + +func NewClient(vppConn api.Connection) networkservice.NetworkServiceClient { + return &l2vtrClient{vppConn: vppConn} +} + +func (v *l2vtrClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { + postponeCtxFunc := postpone.ContextWithValues(ctx) + + conn, err := next.Client(ctx).Request(ctx, request, opts...) + if err != nil { + return nil, err + } + + if err = enableVtr(ctx, conn, v.vppConn); err != nil { + closeCtx, cancelClose := postponeCtxFunc() + defer cancelClose() + + if _, closeErr := v.Close(closeCtx, conn, opts...); closeErr != nil { + err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error()) + } + + return nil, err + } + + return conn, nil +} + +func (v *l2vtrClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { + _ = disableVtr(ctx, conn, v.vppConn) + return next.Client(ctx).Close(ctx, conn, opts...) +} + +func enableVtr(ctx context.Context, conn *networkservice.Connection, vppConn api.Connection) error { + if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { + swIfIndex, ok := ifindex.Load(ctx, true) + if !ok { + return nil + } + now := time.Now() + if _, err := l2.NewServiceClient(vppConn).L2InterfaceVlanTagRewrite(ctx, &l2.L2InterfaceVlanTagRewrite{ + SwIfIndex: swIfIndex, + VtrOp: L2_VTR_POP_1, + PushDot1q: 0, + Tag1: 0, + Tag2: 0, + }); err != nil { + return errors.WithStack(err) + } + log.FromContext(ctx). + WithField("duration", time.Since(now)). + WithField("SwIfIndex", swIfIndex). + WithField("operation", "POP 1"). + WithField("vppapi", "L2InterfaceVlanTagRewrite").Debug("completed") + + } + return nil +} + +func disableVtr(ctx context.Context, conn *networkservice.Connection, vppConn api.Connection) error { + if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { + swIfIndex, ok := ifindex.Load(ctx, true) + if !ok { + return nil + } + now := time.Now() + + if _, err := l2.NewServiceClient(vppConn).L2InterfaceVlanTagRewrite(ctx, &l2.L2InterfaceVlanTagRewrite{ + SwIfIndex: swIfIndex, + VtrOp: L2_VTR_DISABLED, + }); err != nil { + return errors.WithStack(err) + } + log.FromContext(ctx). + WithField("duration", time.Since(now)). + WithField("SwIfIndex", swIfIndex). + WithField("operation", "DISABLE"). + WithField("vppapi", "L2InterfaceVlanTagRewrite").Debug("completed") + + } + return nil +} diff --git a/pkg/networkservice/mechanisms/vlan/l2vtr/constants.go b/pkg/networkservice/mechanisms/vlan/l2vtr/constants.go new file mode 100644 index 00000000..6304f35d --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/l2vtr/constants.go @@ -0,0 +1,24 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 l2vtr + +// defines enum 'vtr_op'. +const ( + L2_VTR_DISABLED uint32 = 0 + L2_VTR_POP_1 uint32 = 3 + L2_VTR_PUSH_DOT1Q uint32 = 1 +) diff --git a/pkg/networkservice/mechanisms/vlan/l2vtr/doc.go b/pkg/networkservice/mechanisms/vlan/l2vtr/doc.go new file mode 100644 index 00000000..9a01ead8 --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/l2vtr/doc.go @@ -0,0 +1,18 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 l2vtr provides chain elements for setting Vlan Tag Rewrite on subinterfaces +package l2vtr diff --git a/pkg/networkservice/mechanisms/vlan/linkinit/client.go b/pkg/networkservice/mechanisms/vlan/linkinit/client.go new file mode 100644 index 00000000..fb89a016 --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/linkinit/client.go @@ -0,0 +1,188 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 linkinit + +import ( + "context" + "io" + "time" + + "git.fd.io/govpp.git/api" + interfaces "github.com/edwarnicke/govpp/binapi/interface" + "github.com/edwarnicke/govpp/binapi/interface_types" + "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" + "github.com/vishvananda/netlink" + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + vlanmech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/vlan" + kernellink "github.com/networkservicemesh/sdk-kernel/pkg/kernel" + "github.com/networkservicemesh/sdk-kernel/pkg/kernel/tools/nshandle" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/tools/log" + "github.com/networkservicemesh/sdk/pkg/tools/postpone" + + "github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan/pciaddresspool" + "github.com/networkservicemesh/sdk-vpp/pkg/tools/initvpp" +) + +type linkinitClient struct { + vppConn api.Connection +} + +// NewClient - creates links for vlan remote mechanism +func NewClient(vppConn api.Connection) networkservice.NetworkServiceClient { + return &linkinitClient{vppConn: vppConn} +} + +func (l *linkinitClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { + postponeCtxFunc := postpone.ContextWithValues(ctx) + + conn, err := next.Client(ctx).Request(ctx, request, opts...) + if err != nil { + return nil, err + } + + if err = initLink(ctx, conn, l.vppConn); err != nil { + closeCtx, cancelClose := postponeCtxFunc() + defer cancelClose() + + if _, closeErr := l.Close(closeCtx, conn, opts...); closeErr != nil { + err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error()) + } + + return nil, err + } + + return conn, nil +} + +func (l *linkinitClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { + _ = unsetLink(ctx, conn) + return next.Client(ctx).Close(ctx, conn, opts...) +} + +func initLink(ctx context.Context, conn *networkservice.Connection, vppConn api.Connection) error { + if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { + kernelLink, err := getKernelLink(ctx) + if err != nil { + return err + } + hostIFName := kernelLink.GetName() + link := kernelLink.GetLink() + log.FromContext(ctx).WithField("linkinit", "Request").Debugf("initLink", hostIFName) + client, err := interfaces.NewServiceClient(vppConn).SwInterfaceDump(ctx, &interfaces.SwInterfaceDump{ + NameFilterValid: true, + NameFilter: hostIFName, + }) + if err == nil { + _, err = client.Recv() + /* No interface found, it can be created */ + if err == io.EOF { + err = createInterface(ctx, vppConn, link) + if err != nil { + return errors.Wrapf(err, "error attempting to create AF_PACKET inteface") + } + } + } else { + return errors.Wrapf(err, "error attempting to get interface dump client create AF_PACKET inteface") + } + + // Set promiscuous mode + now := time.Now() + + err = netlink.SetPromiscOn(link) + if err != nil { + log.FromContext(ctx). + WithField("duration", time.Since(now)). + WithField("HostInterfaceName", hostIFName). + WithField("netlink", "SetPromiscOn"). + Warn("Promiscuous mode not set!") + } else { + log.FromContext(ctx). + WithField("duration", time.Since(now)). + WithField("HostInterfaceName", hostIFName). + WithField("netlink", "SetPromiscOn").Debug("completed") + } + } + return nil +} + +func unsetLink(ctx context.Context, conn *networkservice.Connection) error { + if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { + now := time.Now() + kernelLink, err := getKernelLink(ctx) + if err != nil { + return err + } + link := kernelLink.GetLink() + + // Set promiscuous mode + err = netlink.SetPromiscOff(link) + if err != nil { + log.FromContext(ctx).Warn("Promiscuous mode not set OFF!") + } + log.FromContext(ctx). + WithField("duration", time.Since(now)). + WithField("HostInterfaceName", link.Attrs().Name). + WithField("netlink", "SetPromiscOff").Debug("completed") + } + return nil +} + +func getKernelLink(ctx context.Context) (kernellink.Link, error) { + pciAddressInfo, ok := pciaddresspool.Load(ctx) + if !ok { + return nil, errors.Errorf("no link found") + } + hostNetNS, err := nshandle.Current() + if err != nil { + return nil, err + } + defer func() { _ = hostNetNS.Close() }() + kernelLink, err := kernellink.FindHostDevice(pciAddressInfo.GetPCIAddress(), "", hostNetNS) + if err != nil { + return nil, err + } + return kernelLink, nil +} + +func createInterface(ctx context.Context, vppConn api.Connection, link netlink.Link) error { + swIfIndex, err := initvpp.CreateAfPacket(ctx, vppConn, link) + if err != nil { + return err + } + + if aclErr := initvpp.DenyAllACLToInterface(ctx, vppConn, swIfIndex); aclErr != nil { + return aclErr + } + + now := time.Now() + _, err = interfaces.NewServiceClient(vppConn).SwInterfaceSetFlags(ctx, &interfaces.SwInterfaceSetFlags{ + SwIfIndex: swIfIndex, + Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP, + }) + if err != nil { + return err + } + log.FromContext(ctx). + WithField("swIfIndex", swIfIndex). + WithField("duration", time.Since(now)). + WithField("vppapi", "SwInterfaceSetFlags").Debug("completed") + return nil +} diff --git a/pkg/networkservice/mechanisms/vlan/linkinit/doc.go b/pkg/networkservice/mechanisms/vlan/linkinit/doc.go new file mode 100644 index 00000000..ec770b2c --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/linkinit/doc.go @@ -0,0 +1,18 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 linkinit provides chain elements for setting link to AF_PACKET interface if it is not already set +package linkinit diff --git a/pkg/networkservice/mechanisms/vlan/pciaddresspool/client.go b/pkg/networkservice/mechanisms/vlan/pciaddresspool/client.go new file mode 100644 index 00000000..f7426748 --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/pciaddresspool/client.go @@ -0,0 +1,116 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 pciaddresspool provides chain elements to select and free PCI Addresses from pool +package pciaddresspool + +import ( + "context" + "sync" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/pkg/errors" + "google.golang.org/grpc" + + "github.com/networkservicemesh/api/pkg/api/networkservice" + vlanmech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/vlan" + "github.com/networkservicemesh/sdk/pkg/networkservice/core/next" + "github.com/networkservicemesh/sdk/pkg/tools/log" + "github.com/networkservicemesh/sdk/pkg/tools/postpone" +) + +const ( + serviceDomainLabel = "serviceDomain" +) + +// PCIAddressPool is an interface of domain.Pool +type PCIAddressPool interface { + Select(tokenName string) (string, error) + Free(tokenName string) +} + +type pciAddressPoolClient struct { + resourceLock sync.Locker + pciAddressPool PCIAddressPool +} + +// NewClient returns a new resource pool client chain element +func NewClient( + resourceLock sync.Locker, + pciAddressPool PCIAddressPool) networkservice.NetworkServiceClient { + return &pciAddressPoolClient{ + resourceLock: resourceLock, + pciAddressPool: pciAddressPool, + } +} + +func (r *pciAddressPoolClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) { + log.FromContext(ctx).WithField("pciAddressPoolClient", "Request").Debug("called") + postponeCtxFunc := postpone.ContextWithValues(ctx) + + conn, err := next.Client(ctx).Request(ctx, request, opts...) + if err != nil { + return nil, err + } + + if err = r.setPCIAddress(ctx, conn); err != nil { + closeCtx, cancelClose := postponeCtxFunc() + defer cancelClose() + + if _, closeErr := r.Close(closeCtx, conn, opts...); closeErr != nil { + err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error()) + } + return nil, err + } + + return conn, nil +} + +func (r *pciAddressPoolClient) setPCIAddress(ctx context.Context, conn *networkservice.Connection) error { + logger := log.FromContext(ctx).WithField("pciAddressPoolClient", "Request") + if mechanism := vlanmech.ToMechanism(conn.GetMechanism()); mechanism != nil { + r.resourceLock.Lock() + defer r.resourceLock.Unlock() + + tokenName := conn.GetLabels()[serviceDomainLabel] + pfPCIAddr, err := r.pciAddressPool.Select(tokenName) + if err != nil { + return errors.Wrapf(err, "failed to select PF for: %s", tokenName) + } + logger.Debugf("Got PCIAddress %v for tokenName %s", pfPCIAddr, tokenName) + + store(ctx, PCIAddressInfo{ + pciAddress: pfPCIAddr, + tokenName: tokenName, + }) + } + return nil +} + +func (r *pciAddressPoolClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) { + r.close(ctx) + return next.Client(ctx).Close(ctx, conn, opts...) +} + +func (r *pciAddressPoolClient) close(ctx context.Context) { + pciAddressInfo, ok := loadAndDelete(ctx) + if !ok { + return + } + r.resourceLock.Lock() + defer r.resourceLock.Unlock() + r.pciAddressPool.Free(pciAddressInfo.tokenName) +} diff --git a/pkg/networkservice/mechanisms/vlan/pciaddresspool/metadata.go b/pkg/networkservice/mechanisms/vlan/pciaddresspool/metadata.go new file mode 100644 index 00000000..eadb4f38 --- /dev/null +++ b/pkg/networkservice/mechanisms/vlan/pciaddresspool/metadata.go @@ -0,0 +1,61 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 pciaddresspool + +import ( + "context" + + "github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata" +) + +type key struct{} + +// PCIAddressInfo store the PCI Address assigned to sarvice domain +type PCIAddressInfo struct { + pciAddress string + tokenName string +} + +func store(ctx context.Context, pciAddressInfo PCIAddressInfo) { + metadata.Map(ctx, true).Store(key{}, pciAddressInfo) +} + +// Load returns the base PCI address stored in per Connection.Id metadata, or nil if no +// value is present. +// The ok result indicates whether value was found in the per Connection.Id metadata. +func Load(ctx context.Context) (value PCIAddressInfo, ok bool) { + rawValue, ok := metadata.Map(ctx, true).Load(key{}) + if !ok { + return + } + value, ok = rawValue.(PCIAddressInfo) + return value, ok +} + +func loadAndDelete(ctx context.Context) (value PCIAddressInfo, ok bool) { + rawValue, ok := metadata.Map(ctx, true).LoadAndDelete(key{}) + if !ok { + return + } + value, ok = rawValue.(PCIAddressInfo) + return value, ok +} + +// GetPCIAddress returns the pci address +func (pai *PCIAddressInfo) GetPCIAddress() string { + return pai.pciAddress +} diff --git a/pkg/tools/domain/config.yml b/pkg/tools/domain/config.yml new file mode 100644 index 00000000..8d5783d5 --- /dev/null +++ b/pkg/tools/domain/config.yml @@ -0,0 +1,16 @@ +physicalFunctions: + 0000:00:04.0: + pfKernelDriver: pf-driver + vfKernelDriver: vf-driver + capabilities: + - default + serviceDomains: + - service.domain.1 + 0000:00:05.0: + pfKernelDriver: pf-driver + vfKernelDriver: vf-driver + capabilities: + - default + serviceDomains: + - service.domain.1 + - service.domain.2 diff --git a/pkg/tools/domain/pool.go b/pkg/tools/domain/pool.go new file mode 100644 index 00000000..62750b4c --- /dev/null +++ b/pkg/tools/domain/pool.go @@ -0,0 +1,125 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 domain provides a pool for service domain to PCI address mappings +package domain + +import ( + "sort" + "strings" + + "github.com/pkg/errors" + + "github.com/networkservicemesh/sdk-sriov/pkg/sriov/config" +) + +// Pool manages the service domain to PCI address mapping +// WARNING: it is thread unsafe - if you want to use it concurrently, use some synchronization outside +type Pool struct { + pciInfos map[string]*pciInfo + pciToSDomain map[string]*serviceDomain +} + +type pciInfo struct { + pfPCIAddr string + freeDomainCount int +} + +type serviceDomain struct { + pcis []*pciInfo + selectedPfPCIAddr string +} + +// NewPool returns a new Pool +func NewPool(cfg *config.Config) *Pool { + p := &Pool{ + pciInfos: map[string]*pciInfo{}, + pciToSDomain: map[string]*serviceDomain{}, + } + for pfPCIAddr, pFun := range cfg.PhysicalFunctions { + pci := &pciInfo{ + pfPCIAddr: pfPCIAddr, + freeDomainCount: len(pFun.ServiceDomains), + } + p.pciInfos[pfPCIAddr] = pci + for _, sDomain := range pFun.ServiceDomains { + sd := p.pciToSDomain[sDomain] + if sd == nil { + sd = &serviceDomain{ + pcis: []*pciInfo{}, + selectedPfPCIAddr: "", + } + p.pciToSDomain[sDomain] = sd + } + sd.pcis = append(sd.pcis, pci) + } + } + return p +} + +// Select selects a physical function for the given driver type +func (p *Pool) Select(tokenName string) (string, error) { + if _, ok := p.pciToSDomain[tokenName]; !ok { + return "", errors.Errorf("no domain found: %s", tokenName) + } + + selected := p.pciToSDomain[tokenName].selectedPfPCIAddr + if selected != "" { + return selected, nil + } + + toselect := filterAndSort(p.pciToSDomain[tokenName].pcis) + if len(toselect) > 0 { + selected = toselect[0].pfPCIAddr + p.pciToSDomain[tokenName].selectedPfPCIAddr = selected + p.pciInfos[selected].freeDomainCount-- + return selected, nil + } + + // should not happen + return "", errors.Errorf("no free PF find for domain: %s", tokenName) +} + +func filterAndSort(pfs []*pciInfo) []*pciInfo { + toselect := []*pciInfo{} + for j := range pfs { + if pfs[j].freeDomainCount != 0 { + toselect = append(toselect, pfs[j]) + } + } + sort.Slice(toselect, func(i, k int) bool { + switch { + case toselect[i].freeDomainCount < toselect[k].freeDomainCount: + return true + case toselect[i].freeDomainCount > toselect[k].freeDomainCount: + return false + default: + return strings.Compare(toselect[i].pfPCIAddr, toselect[k].pfPCIAddr) < 0 + } + }) + return toselect +} + +// Free re-add the domain to the pool and free the assigned PCI address +func (p *Pool) Free(tokenName string) { + if _, ok := p.pciToSDomain[tokenName]; ok { + selected := p.pciToSDomain[tokenName].selectedPfPCIAddr + if selected != "" { + p.pciInfos[selected].freeDomainCount++ + p.pciToSDomain[tokenName].selectedPfPCIAddr = "" + } + } +} diff --git a/pkg/tools/domain/pool_test.go b/pkg/tools/domain/pool_test.go new file mode 100644 index 00000000..a496d90e --- /dev/null +++ b/pkg/tools/domain/pool_test.go @@ -0,0 +1,119 @@ +// Copyright (c) 2021 Nordix Foundation. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 domain_test + +import ( + "context" + "testing" + + "github.com/networkservicemesh/sdk-sriov/pkg/sriov/config" + "github.com/stretchr/testify/require" + + "github.com/networkservicemesh/sdk-vpp/pkg/tools/domain" +) + +const ( + configFileName = "config.yml" + serviceDomain1 = "service.domain.1" + serviceDomain2 = "service.domain.2" + capability = "default" + pf1PciAddr = "0000:00:04.0" + pf2PciAddr = "0000:00:05.0" +) + +func TestPool_Select_Selected(t *testing.T) { + cfg, err := config.ReadConfig(context.TODO(), configFileName) + require.NoError(t, err) + + p := domain.NewPool(cfg) + + // Should be the same PF for the same domain. + + pfPCIAddr, err := p.Select(serviceDomain1) + require.NoError(t, err) + require.Equal(t, pf1PciAddr, pfPCIAddr) // <-- initial + + pfPCIAddr, err = p.Select(serviceDomain1) + require.NoError(t, err) + require.Equal(t, pf1PciAddr, pfPCIAddr) // <-- same +} + +func TestPool_Select_Other(t *testing.T) { + cfg, err := config.ReadConfig(context.TODO(), configFileName) + require.NoError(t, err) + + p := domain.NewPool(cfg) + + // Should be the same PF for the same domain. + + pfPCIAddr, err := p.Select(serviceDomain1) + require.NoError(t, err) + require.Equal(t, pf1PciAddr, pfPCIAddr) // <-- initial + + pfPCIAddr, err = p.Select(serviceDomain2) + require.NoError(t, err) + require.Equal(t, pf2PciAddr, pfPCIAddr) // <-- different +} + +func TestPool_Select_OtherDifferentOrder(t *testing.T) { + cfg, err := config.ReadConfig(context.TODO(), configFileName) + require.NoError(t, err) + + p := domain.NewPool(cfg) + + // Should be the same PF for the same domain. + + pfPCIAddr, err := p.Select(serviceDomain2) + require.NoError(t, err) + require.Equal(t, pf2PciAddr, pfPCIAddr) // <-- initial + + pfPCIAddr, err = p.Select(serviceDomain1) + require.NoError(t, err) + require.Equal(t, pf1PciAddr, pfPCIAddr) // <-- different +} + +func TestPool_Select_Unknown(t *testing.T) { + cfg, err := config.ReadConfig(context.TODO(), configFileName) + require.NoError(t, err) + + p := domain.NewPool(cfg) + + // Should be the same PF for the same domain. + + pfPCIAddr, err := p.Select(capability) + require.NotNil(t, err, "no domain found: default") + require.Equal(t, "", pfPCIAddr) +} + +func TestPool_Free(t *testing.T) { + cfg, err := config.ReadConfig(context.TODO(), configFileName) + require.NoError(t, err) + + p := domain.NewPool(cfg) + + // Should be the same PF for the same domain. + + pfPCIAddr, err := p.Select(serviceDomain1) + require.NoError(t, err) + require.Equal(t, pf1PciAddr, pfPCIAddr) // <-- initial + + p.Free(serviceDomain1) + + pfPCIAddr, err = p.Select(serviceDomain1) + require.NoError(t, err) + require.Equal(t, pf1PciAddr, pfPCIAddr) // <-- same +}