diff --git a/go.mod b/go.mod index 9d16e307..a9a94fa9 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,10 @@ require ( golang.org/x/sys v0.11.0 // exclude ) -require github.com/golang/mock v1.6.0 +require ( + github.com/florianl/go-tc v0.4.2 + github.com/golang/mock v1.6.0 +) require ( github.com/KyleBanks/depth v1.2.1 // indirect @@ -26,17 +29,22 @@ require ( github.com/go-openapi/spec v0.20.8 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/josharian/native v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mdlayher/netlink v1.6.0 // indirect + github.com/mdlayher/socket v0.1.1 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a // indirect golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect golang.org/x/net v0.9.0 // indirect + golang.org/x/sync v0.2.0 // indirect golang.org/x/tools v0.8.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 605bc599..e07ac792 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,9 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -11,6 +14,10 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/florianl/go-tc v0.4.2 h1:jan5zcOWCLhA9SRBHZhQ0SSAq7cmDUagiRPngAi5AOQ= +github.com/florianl/go-tc v0.4.2/go.mod h1:2W1jSMFryiYlpQigr4ZpSSpE9XNze+bW7cTsCXWbMwo= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= @@ -35,12 +42,35 @@ github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgj github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= +github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= +github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= +github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= +github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= +github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= +github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786 h1:N527AHMa793TP5z5GNAn/VLPzlc0ewzWdeP/25gDfgQ= +github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -57,6 +87,23 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= +github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= +github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= +github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= +github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= +github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= +github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= +github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= +github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0= +github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= +github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= +github.com/mdlayher/socket v0.1.1 h1:q3uOGirUPfAV2MUoaC7BavjQ154J7+JOkTWyiV+intI= +github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -73,6 +120,7 @@ github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+Pymzi github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/robfig/config v0.0.0-20141207224736-0f78529c8c7e h1:3/9k/etUfgykjM3Rx8X0echJzo7gNNeND/ubPkqYw1k= github.com/robfig/config v0.0.0-20141207224736-0f78529c8c7e/go.mod h1:Zerq1qYbCKtIIU9QgPydffGlpYfZ8KI/si49wuTLY/Q= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= @@ -97,34 +145,71 @@ github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKik github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +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-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +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/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -143,6 +228,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/kf/bpf.go b/kf/bpf.go index d7cccedf..01b2c655 100644 --- a/kf/bpf.go +++ b/kf/bpf.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" "io" + "net" "net/http" "net/url" "os" @@ -31,6 +32,9 @@ import ( "github.com/l3af-project/l3afd/stats" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/link" + "github.com/cilium/ebpf/rlimit" + tc "github.com/florianl/go-tc" ps "github.com/mitchellh/go-ps" "github.com/rs/zerolog/log" ) @@ -49,18 +53,22 @@ const fileScheme string = "file" // BPF defines run time details for BPFProgram. type BPF struct { - Program models.BPFProgram - Cmd *exec.Cmd `json:"-"` - FilePath string // Binary file path - RestartCount int // To track restart count - PrevMapNamePath string // Previous Map name with path to link - MapNamePath string // Map name with path - ProgID int // eBPF Program ID - BpfMaps map[string]BPFMap // Config maps passed as map-args, Map name is Key - MetricsBpfMaps map[string]*MetricsBPFMap // Metrics map name+key+aggregator is key - Ctx context.Context `json:"-"` - Done chan bool `json:"-"` - hostConfig *config.Config + Program models.BPFProgram + Cmd *exec.Cmd `json:"-"` + FilePath string // Binary file path + RestartCount int // To track restart count + PrevMapNamePath string // Previous Map name with path to link + MapNamePath string // Map name with path + ProgID ebpf.ProgramID // eBPF Program ID + BpfMaps map[string]BPFMap // Config maps passed as map-args, Map name is Key + MetricsBpfMaps map[string]*MetricsBPFMap // Metrics map name+key+aggregator is key + Ctx context.Context `json:"-"` + Done chan bool `json:"-"` + ProgMapCollection *ebpf.Collection `json:"_"` // eBPF Collection reference + ProgMapID ebpf.MapID + hostConfig *config.Config + TCFilter *tc.Filter `json:"-"` // handle to tc filter + XDPLink link.Link `json:"-"` // handle xdp link object } func NewBpfProgram(ctx context.Context, program models.BPFProgram, conf *config.Config) *BPF { @@ -95,8 +103,6 @@ func LoadRootProgram(ifaceName string, direction string, progType string, conf * MapName: conf.XDPRootMapName, Version: conf.XDPRootVersion, UserProgramDaemon: false, - CmdStart: conf.XDPRootCommand, - CmdStop: conf.XDPRootCommand, CmdStatus: "", AdminStatus: models.Enabled, ProgType: models.XDPType, @@ -104,6 +110,8 @@ func LoadRootProgram(ifaceName string, direction string, progType string, conf * StartArgs: map[string]interface{}{}, StopArgs: map[string]interface{}{}, StatusArgs: map[string]interface{}{}, + ObjectFile: filepath.Join(conf.BPFDir, conf.XDPRootPackageName, conf.XDPRootVersion, strings.Split(conf.XDPRootArtifact, ".")[0], conf.XDPRootObjectFile), + EntryFunctionName: conf.XDPRootEntryFunctionName, }, RestartCount: 0, Cmd: nil, @@ -111,6 +119,7 @@ func LoadRootProgram(ifaceName string, direction string, progType string, conf * PrevMapNamePath: "", hostConfig: conf, MapNamePath: filepath.Join(conf.BpfMapDefaultPath, conf.XDPRootMapName), + XDPLink: nil, } case models.TCType: rootProgBPF = &BPF{ @@ -119,8 +128,6 @@ func LoadRootProgram(ifaceName string, direction string, progType string, conf * Artifact: conf.TCRootArtifact, Version: conf.TCRootVersion, UserProgramDaemon: false, - CmdStart: conf.TCRootCommand, - CmdStop: conf.TCRootCommand, CmdStatus: "", AdminStatus: models.Enabled, ProgType: models.TCType, @@ -137,34 +144,39 @@ func LoadRootProgram(ifaceName string, direction string, progType string, conf * if direction == models.IngressType { rootProgBPF.Program.MapName = conf.TCRootIngressMapName rootProgBPF.MapNamePath = filepath.Join(conf.BpfMapDefaultPath, conf.TCRootIngressMapName) + rootProgBPF.Program.ObjectFile = filepath.Join(conf.BPFDir, conf.TCRootPackageName, conf.TCRootVersion, strings.Split(conf.TCRootArtifact, ".")[0], conf.TCRootIngressObjectFile) + rootProgBPF.Program.EntryFunctionName = conf.TCRootIngressEntryFunctionName } else if direction == models.EgressType { rootProgBPF.Program.MapName = conf.TCRootEgressMapName rootProgBPF.MapNamePath = filepath.Join(conf.BpfMapDefaultPath, conf.TCRootEgressMapName) + rootProgBPF.Program.ObjectFile = filepath.Join(conf.BPFDir, conf.TCRootPackageName, conf.TCRootVersion, strings.Split(conf.TCRootArtifact, ".")[0], conf.TCRootEgressObjectFile) + rootProgBPF.Program.EntryFunctionName = conf.TCRootEgressEntryFunctionName } default: return nil, fmt.Errorf("unknown direction %s for root program in iface %s", direction, ifaceName) } - // Loading default arguments - rootProgBPF.Program.StartArgs["cmd"] = models.StartType - rootProgBPF.Program.StopArgs["cmd"] = models.StopType - if err := rootProgBPF.VerifyAndGetArtifacts(conf); err != nil { log.Error().Err(err).Msg("failed to get root artifacts") return nil, err } // On l3afd crashing scenario verify root program are unloaded properly by checking existence of persisted maps - // if map file exists then root program is still running + // if map file exists then root program didn't clean up pinned map files if fileExists(rootProgBPF.MapNamePath) { - log.Warn().Msgf("previous instance of root program %s is running, stopping it ", rootProgBPF.Program.Name) - if err := rootProgBPF.Stop(ifaceName, direction, conf.BpfChainingEnabled); err != nil { - return nil, fmt.Errorf("failed to stop root program on iface %s name %s direction %s", ifaceName, rootProgBPF.Program.Name, direction) - } + log.Warn().Msgf("previous instance of root program %s persisted map %s file exists", rootProgBPF.Program.Name, rootProgBPF.MapNamePath) + rootProgBPF.RemoveMapFile() } - if err := rootProgBPF.Start(ifaceName, direction, conf.BpfChainingEnabled); err != nil { - return nil, fmt.Errorf("failed to start root program on interface %s, err: %v", ifaceName, err) + if progType == models.XDPType { + rlimit.RemoveMemlock() + if err := rootProgBPF.LoadXDPAttachProgram(ifaceName, rootProgBPF); err != nil { + return nil, fmt.Errorf("failed to load root program on iface \"%s\" name %s direction %s", ifaceName, rootProgBPF.Program.Name, direction) + } + } else if progType == models.TCType { + if err := rootProgBPF.LoadTCAttachProgram(ifaceName, direction, rootProgBPF); err != nil { + return nil, fmt.Errorf("failed to load root program on iface \"%s\" name %s direction %s", ifaceName, rootProgBPF.Program.Name, direction) + } } return rootProgBPF, nil @@ -242,7 +254,17 @@ func (b *BPF) Stop(ifaceName, direction string, chain bool) error { // Setting NFRunning to 0, indicates not running stats.SetWithVersion(0.0, stats.NFRunning, b.Program.Name, b.Program.Version, direction, ifaceName) + // First preference to unload/stop from l3afd + if b.ProgMapCollection != nil { + if err := b.UnloadProgram(ifaceName, direction); err != nil { + return fmt.Errorf("BPFProgram %s unload failed on interface %s with error: %v", b.Program.Name, ifaceName, err) + } + log.Info().Msgf("%s => %s direction => %s - program is unloaded/detached successfully", ifaceName, b.Program.Name, direction) + return nil + } + if len(b.Program.CmdStop) < 1 { + // Loaded using user program if err := b.ProcessTerminate(); err != nil { return fmt.Errorf("BPFProgram %s process terminate failed with error: %v", b.Program.Name, err) } @@ -253,16 +275,9 @@ func (b *BPF) Stop(ifaceName, direction string, chain bool) error { b.Cmd = nil } - // verify pinned map file is removed. - if err := b.VerifyPinnedMapVanish(chain); err != nil { - log.Error().Err(err).Msgf("stop user program - failed to remove pinned file %s", b.Program.Name) - return fmt.Errorf("stop user program - failed to remove pinned file %s", b.Program.Name) - } - - // Verify all metrics map references are removed from kernel - if err := b.VerifyMetricsMapsVanish(); err != nil { - log.Error().Err(err).Msgf("stop user program - failed to remove metric map references %s", b.Program.Name) - return fmt.Errorf("stop user program - failed to remove metric map references %s", b.Program.Name) + if err := b.VerifyCleanupMaps(chain); err != nil { + log.Error().Err(err).Msgf("stop user program - failed to remove map files %s", b.Program.Name) + return fmt.Errorf("stop user program - failed to remove map files %s", b.Program.Name) } return nil @@ -295,16 +310,9 @@ func (b *BPF) Stop(ifaceName, direction string, chain bool) error { } b.Cmd = nil - // verify pinned map file is removed. - if err := b.VerifyPinnedMapVanish(chain); err != nil { - log.Error().Err(err).Msgf("failed to remove pinned file %s", b.Program.Name) - return fmt.Errorf("failed to remove pinned file %s", b.Program.Name) - } - - // Verify all metrics map references are removed from kernel - if err := b.VerifyMetricsMapsVanish(); err != nil { - log.Error().Err(err).Msgf("failed to remove metric map references %s", b.Program.Name) - return fmt.Errorf("failed to remove metric map references %s", b.Program.Name) + if err := b.VerifyCleanupMaps(chain); err != nil { + log.Error().Err(err).Msgf("stop user program - failed to remove map files %s", b.Program.Name) + return fmt.Errorf("stop user program - failed to remove map files %s", b.Program.Name) } return nil @@ -435,7 +443,7 @@ func (b *BPF) Start(ifaceName, direction string, chain bool) error { // KFconfigs if len(b.Program.CmdConfig) > 0 && len(b.Program.ConfigFilePath) > 0 { - log.Info().Msgf("KP specific config monitoring - %s", b.Program.ConfigFilePath) + log.Info().Msgf("eBPF program specific config monitoring - %s", b.Program.ConfigFilePath) b.Done = make(chan bool) go b.RunKFConfigs() } @@ -931,7 +939,7 @@ func (b *BPF) PutNextProgFDFromID(progID int) error { } // GetProgID - This returns ID of the bpf program -func (b *BPF) GetProgID() (int, error) { +func (b *BPF) GetProgID() (ebpf.ProgramID, error) { ebpfMap, err := ebpf.LoadPinnedMap(b.PrevMapNamePath, &ebpf.LoadPinOptions{ReadOnly: true}) if err != nil { @@ -939,12 +947,12 @@ func (b *BPF) GetProgID() (int, error) { return 0, fmt.Errorf("unable to access pinned prog map %s %v", b.PrevMapNamePath, err) } defer ebpfMap.Close() - var value int + var value ebpf.ProgramID key := 0 if err = ebpfMap.Lookup(unsafe.Pointer(&key), unsafe.Pointer(&value)); err != nil { - log.Warn().Err(err).Msgf("unable to lookup prog map %s", b.PrevMapNamePath) - return 0, fmt.Errorf("unable to lookup prog map %v", err) + log.Warn().Err(err).Msgf("unable to look up prog map %s", b.PrevMapNamePath) + return 0, fmt.Errorf("unable to look up prog map %v", err) } // verify progID before storing in locally. @@ -1098,6 +1106,123 @@ func (b *BPF) VerifyMetricsMapsVanish() error { return err } +// LoadXDPAttachProgram - Load and attach xdp root program or any xdp program when chaining is disabled +func (b *BPF) LoadXDPAttachProgram(ifaceName string, eBPFProgram *BPF) error { + iface, err := net.InterfaceByName(ifaceName) + if err != nil { + log.Fatal().Msgf("look up network iface %q: %s", ifaceName, err) + } + + CollectionRef, err := ebpf.LoadCollection(eBPFProgram.Program.ObjectFile) + if err != nil { + return fmt.Errorf("%s: loading of xdp root failed", eBPFProgram.Program.ObjectFile) + } + + b.ProgMapCollection = CollectionRef + bpfRootProg := CollectionRef.Programs[eBPFProgram.Program.EntryFunctionName] + bpfRootMap := CollectionRef.Maps[eBPFProgram.Program.MapName] + + // Pinning root map + if b.hostConfig.BpfChainingEnabled { + rootArrayMapFileName := filepath.Join(b.hostConfig.BpfMapDefaultPath, eBPFProgram.Program.MapName) + if err := bpfRootMap.Pin(rootArrayMapFileName); err != nil { + return fmt.Errorf("%s:failed to pin the map", rootArrayMapFileName) + } + } + + b.XDPLink, err = link.AttachXDP(link.XDPOptions{ + Program: bpfRootProg, + Interface: iface.Index, + }) + + if err != nil { + return fmt.Errorf("could not attach xdp program %s to interface %s : %v", b.Program.Name, ifaceName, err) + } + + progInfo, err := bpfRootProg.Info() + if err != nil { + return fmt.Errorf("could not get program info of %s to interface %s : %v", b.Program.Name, ifaceName, err) + } + + ok := false + b.ProgID, ok = progInfo.ID() + if !ok { + return fmt.Errorf("failed to fetch the xdp program %s to interface %s : %v", b.Program.Name, ifaceName, err) + } + + ebpfInfo, err := bpfRootMap.Info() + if err != nil { + return fmt.Errorf("fetching map info failed for xdp program %s to interface %s : %v", b.Program.Name, ifaceName, err) + } + + b.ProgMapID, ok = ebpfInfo.ID() + if !ok { + return fmt.Errorf("fetching map id failed for xdp program %s to interface %s : %v", b.Program.Name, ifaceName, err) + } + + return nil +} + +// UnloadProgram - Unload or detach the program from the interface and close all the program resources +// TODO: Before unloading make sure user program is stopped to avoid any errors +func (b *BPF) UnloadProgram(ifaceName, direction string) error { + _, err := net.InterfaceByName(ifaceName) + if err != nil { + log.Fatal().Msgf("look up network iface %q: %s", ifaceName, err) + } + + // Verifying program attached to the interface. + // SeqID will be 0 for root program or any other program without chaining + if b.Program.SeqID == 0 || !b.hostConfig.BpfChainingEnabled { + if b.Program.ProgType == models.TCType { + if err := b.UnloadTCProgram(ifaceName, direction); err != nil { + log.Warn().Msgf("removing tc filter failed iface %q direction %s error - %v", ifaceName, direction, err) + } + } else if b.Program.ProgType == models.XDPType { + if err := b.XDPLink.Close(); err != nil { + log.Warn().Msgf("removing xdp attached program failed iface %q direction %s error - %v", ifaceName, direction, err) + } + } + } + + // Release all the resources of the epbf program + if b.ProgMapCollection != nil { + b.ProgMapCollection.Close() + } + + // remove pinned map file + if err := b.RemoveMapFile(); err != nil { + log.Error().Msgf("failed to remove map file for program %s => %s", ifaceName, b.Program.Name) + } + + return nil +} + +func (b *BPF) RemoveMapFile() error { + if err := os.RemoveAll(b.MapNamePath); os.IsNotExist(err) { + log.Info().Msgf("RemoveMapFile: map file removed successfully - %s ", b.MapNamePath) + return nil + } + return nil +} + +// VerifyCleanupMaps - This method verifies map entries in the fs is removed +func (b *BPF) VerifyCleanupMaps(chain bool) error { + // verify pinned map file is removed. + if err := b.VerifyPinnedMapVanish(chain); err != nil { + log.Error().Err(err).Msgf("stop user program - failed to remove pinned file %s", b.Program.Name) + return fmt.Errorf("stop user program - failed to remove pinned file %s", b.Program.Name) + } + + // Verify all metrics map references are removed from kernel + if err := b.VerifyMetricsMapsVanish(); err != nil { + log.Error().Err(err).Msgf("stop user program - failed to remove metric map references %s", b.Program.Name) + return fmt.Errorf("stop user program - failed to remove metric map references %s", b.Program.Name) + } + + return nil +} + func ValidatePath(filePath string, destination string) (string, error) { destpath := filepath.Join(destination, filePath) if strings.Contains(filePath, "..") { diff --git a/kf/kf_unix.go b/kf/kf_unix.go index f35f11ab..ccda798f 100644 --- a/kf/kf_unix.go +++ b/kf/kf_unix.go @@ -11,11 +11,18 @@ import ( "bytes" "errors" "fmt" + "net" "os" + "path/filepath" "strings" "syscall" "unsafe" + "github.com/l3af-project/l3afd/models" + + "github.com/cilium/ebpf" + "github.com/florianl/go-tc" + "github.com/florianl/go-tc/core" "github.com/rs/zerolog/log" "github.com/safchain/ethtool" "golang.org/x/sys/unix" @@ -194,3 +201,171 @@ func VerifyNCreateTCDirs() error { } return nil } + +// LoadTCAttachProgram - Load and attach tc root program filters or any tc program when chaining is disabled +func (b *BPF) LoadTCAttachProgram(ifaceName, direction string, eBPFProgram *BPF) error { + iface, err := net.InterfaceByName(ifaceName) + if err != nil { + log.Fatal().Msgf("look up network iface %q: %s", ifaceName, err) + } + + // verify and add attribute clsact + tcgo, err := tc.Open(&tc.Config{}) + if err != nil { + return fmt.Errorf("could not open rtnetlink socket for interface %s : %v", ifaceName, err) + } + + clsactFound := false + // get all the qdiscs from all interfaces + qdiscs, err := tcgo.Qdisc().Get() + if err != nil { + return fmt.Errorf("could not get qdiscs for interface %s : %v", ifaceName, err) + } + for _, qdisc := range qdiscs { + iface, err := net.InterfaceByIndex(int(qdisc.Ifindex)) + if err != nil { + return fmt.Errorf("could not get interface %s from id %d: %v", ifaceName, qdisc.Ifindex, err) + } + if iface.Name == ifaceName && qdisc.Kind == "clsact" { + clsactFound = true + } + } + + if !clsactFound { + qdisc := tc.Object{ + Msg: tc.Msg{ + Family: unix.AF_UNSPEC, + Ifindex: uint32(iface.Index), + Handle: core.BuildHandle(tc.HandleRoot, 0x0000), + Parent: tc.HandleIngress, + Info: 0, + }, + Attribute: tc.Attribute{ + Kind: "clsact", + }, + } + + if err := tcgo.Qdisc().Add(&qdisc); err != nil { + log.Info().Msgf("could not assign clsact to %s : %v, its already exists", ifaceName, err) + } + } + + CollectionRef, err := ebpf.LoadCollection(eBPFProgram.Program.ObjectFile) + if err != nil { + log.Error().Msgf("loading of tc program %s object file %s failed direction %s", eBPFProgram.Program.Name, eBPFProgram.Program.ObjectFile, direction) + return fmt.Errorf("%s : loading of tc program failed", eBPFProgram.Program.ObjectFile) + } + + // Storing collection reference pointer + b.ProgMapCollection = CollectionRef + + var bpfRootProg *ebpf.Program + var bpfRootMap *ebpf.Map + var rootArrayMapFileName string + + bpfRootProg = CollectionRef.Programs[eBPFProgram.Program.EntryFunctionName] + ss := strings.Split(eBPFProgram.Program.MapName, "/") + bpfRootMap = CollectionRef.Maps[ss[len(ss)-1]] + rootArrayMapFileName = filepath.Join(b.hostConfig.BpfMapDefaultPath, eBPFProgram.Program.MapName) + + // Pinning program map + if err := bpfRootMap.Pin(rootArrayMapFileName); err != nil { + return fmt.Errorf("%s failed to pin the map of program %s", rootArrayMapFileName, eBPFProgram.Program.Name) + } + + var parent uint32 + if direction == models.IngressType { + parent = tc.HandleMinIngress + } else if direction == models.EgressType { + parent = tc.HandleMinEgress + } + + progFD := uint32(bpfRootProg.FD()) + // Netlink attribute used in the Linux kernel + bpfFlag := uint32(tc.BpfActDirect) + + filter := tc.Object{ + Msg: tc.Msg{ + Family: unix.AF_UNSPEC, + Ifindex: uint32(iface.Index), + Handle: 0, + Parent: core.BuildHandle(tc.HandleRoot, parent), + Info: 0x300, + }, + Attribute: tc.Attribute{ + Kind: "bpf", + BPF: &tc.Bpf{ + FD: &progFD, + Flags: &bpfFlag, + }, + }, + } + + // Storing Filter handle + b.TCFilter = tcgo.Filter() + + // Attaching / Adding as filter + if err := b.TCFilter.Add(&filter); err != nil { + return fmt.Errorf("could not attach filter to interface %s for eBPF program %s : %v", ifaceName, eBPFProgram.Program.Name, err) + } + + return nil +} + +// UnloadTCProgram - Remove TC filters +func (b *BPF) UnloadTCProgram(ifaceName, direction string) error { + + iface, err := net.InterfaceByName(ifaceName) + if err != nil { + log.Fatal().Msgf("look up network iface %q: %s", ifaceName, err) + } + + bpfRootProg := b.ProgMapCollection.Programs[b.Program.EntryFunctionName] + + var parent uint32 + if direction == models.IngressType { + parent = tc.HandleMinIngress + } else if direction == models.EgressType { + parent = tc.HandleMinEgress + } + + tcfilts, err := b.TCFilter.Get(&tc.Msg{ + Family: unix.AF_UNSPEC, + Ifindex: uint32(iface.Index), + Handle: 0x0, + Parent: core.BuildHandle(tc.HandleRoot, tc.HandleMinIngress), + }) + + if err != nil { + log.Warn().Msgf("Could not get filters for interface \"%s\" direction %s ", ifaceName, direction) + return fmt.Errorf("could not get filters for interface %s : %v", ifaceName, err) + } + + progFD := uint32(bpfRootProg.FD()) + // Netlink attribute used in the Linux kernel + bpfFlag := uint32(tc.BpfActDirect) + + filter := tc.Object{ + Msg: tc.Msg{ + Family: unix.AF_UNSPEC, + Ifindex: uint32(iface.Index), + Handle: 0, + Parent: core.BuildHandle(tc.HandleRoot, parent), + Info: tcfilts[0].Msg.Info, + }, + Attribute: tc.Attribute{ + Kind: "bpf", + BPF: &tc.Bpf{ + FD: &progFD, + Flags: &bpfFlag, + }, + }, + } + + // Detaching / Deleting filter + if err := b.TCFilter.Delete(&filter); err != nil { + return fmt.Errorf("could not dettach tc filter for interface %s : %v", ifaceName, err) + } + + return nil +} diff --git a/kf/kf_windows.go b/kf/kf_windows.go index 978c9bd8..e6459916 100644 --- a/kf/kf_windows.go +++ b/kf/kf_windows.go @@ -55,3 +55,14 @@ func (b *BPF) ProcessTerminate() error { func VerifyNCreateTCDirs() error { return nil } + +// LoadTCAttachProgram - not implemented in windows +func (b *BPF) LoadTCAttachProgram(ifaceName, direction string, eBPFProgram *BPF) error { + // not implement nothing todo + return fmt.Errorf("LoadTCAttachProgram - TC programs Unsupported on windows") +} + +// UnloadTCProgram - Remove TC filters +func (b *BPF) UnloadTCProgram(ifaceName, direction string) error { + return fmt.Errorf("UnloadTCProgram - TC programs Unsupported on windows") +} diff --git a/kf/nfconfig.go b/kf/nfconfig.go index 52c40024..c4a1464b 100644 --- a/kf/nfconfig.go +++ b/kf/nfconfig.go @@ -380,7 +380,7 @@ func (c *NFConfigs) VerifyNUpdateBPFProgram(bpfProg *models.BPFProgram, ifaceNam // update if not a last program if e.Next() != nil { - data.PutNextProgFDFromID(e.Next().Value.(*BPF).ProgID) + data.PutNextProgFDFromID(int(e.Next().Value.(*BPF).ProgID)) } return nil @@ -608,7 +608,7 @@ func (c *NFConfigs) StopRootProgram(ifaceName, direction string) error { func (c *NFConfigs) LinkBPFPrograms(leftBPF, rightBPF *BPF) error { log.Info().Msgf("LinkBPFPrograms : left BPF Prog %s right BPF Prog %s", leftBPF.Program.Name, rightBPF.Program.Name) rightBPF.PrevMapNamePath = leftBPF.MapNamePath - if err := leftBPF.PutNextProgFDFromID(rightBPF.ProgID); err != nil { + if err := leftBPF.PutNextProgFDFromID(int(rightBPF.ProgID)); err != nil { log.Error().Err(err).Msgf("LinkBPFPrograms - failed to update program fd in prev prog map before move") return fmt.Errorf("LinkBPFPrograms - failed to update program fd in prev prog prog map before move %v", err) } @@ -828,32 +828,32 @@ func (c *NFConfigs) RemoveMissingNetIfacesNBPFProgsInConfig(bpfProgCfgs []models _, ok := c.IngressXDPBpfs[ifaceName] if ok { wg.Add(1) - go func() { + go func(bpfProg models.L3afBPFPrograms) { defer wg.Done() if err := c.RemoveMissingBPFProgramsInConfig(bpfProg, ifaceName, models.XDPIngressType); err != nil { log.Error().Err(err).Msgf("Failed to stop missing program for network interface %s direction Ingress", ifaceName) } - }() + }(bpfProg) } _, ok = c.IngressTCBpfs[ifaceName] if ok { wg.Add(1) - go func() { + go func(bpfProg models.L3afBPFPrograms) { defer wg.Done() if err := c.RemoveMissingBPFProgramsInConfig(bpfProg, ifaceName, models.IngressType); err != nil { log.Error().Err(err).Msgf("Failed to stop missing program for network interface %s direction Ingress", ifaceName) } - }() + }(bpfProg) } _, ok = c.EgressTCBpfs[ifaceName] if ok { wg.Add(1) - go func() { + go func(bpfProg models.L3afBPFPrograms) { defer wg.Done() if err := c.RemoveMissingBPFProgramsInConfig(bpfProg, ifaceName, models.EgressType); err != nil { log.Error().Err(err).Msgf("Failed to stop missing program for network interface %s direction Ingress", ifaceName) } - }() + }(bpfProg) } } } diff --git a/kf/nfconfig_test.go b/kf/nfconfig_test.go index 57d9dca8..bc90f55b 100644 --- a/kf/nfconfig_test.go +++ b/kf/nfconfig_test.go @@ -24,7 +24,6 @@ var ( hostInterfaces map[string]bool pMon *pCheck mMon *kfMetrics - // val []byte valVerChange *models.BPFPrograms valStatusChange *models.BPFPrograms ingressXDPBpfs map[string]*list.List