* [PATCH net-next v2 1/2] tools/net/ynl: configuration through json
2023-07-27 12:03 [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration Maryam Tahhan
@ 2023-07-27 12:03 ` Maryam Tahhan
2023-07-28 0:39 ` Jakub Kicinski
2023-07-27 12:03 ` [PATCH net-next v2 2/2] tools/net/ynl: validate config against schema Maryam Tahhan
2023-07-28 0:37 ` [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration Jakub Kicinski
2 siblings, 1 reply; 8+ messages in thread
From: Maryam Tahhan @ 2023-07-27 12:03 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, edumazet, pabeni, Maryam Tahhan
Enable YNL configuration through a json file alongside the
current commandline arguments. This will allow one to cycle
through multiple specs and commands at once.
Signed-off-by: Maryam Tahhan <mtahhan@redhat.com>
---
tools/net/ynl/cli.py | 108 ++++++++++++++++++++++++++++++++++---------
1 file changed, 87 insertions(+), 21 deletions(-)
diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py
index ffaa8038aa8c..1749851f8460 100755
--- a/tools/net/ynl/cli.py
+++ b/tools/net/ynl/cli.py
@@ -5,13 +5,54 @@ import argparse
import json
import pprint
import time
+import os
from lib import YnlFamily
+class ynlConfig():
+ def __init__(self):
+ self.no_schema = True
+ self.schema = None
+ self.spec = None
+ self.json_text = None
+ self.ntf = None
+ self.sleep = None
+ self.do = None
+ self.dump = None
+ def run(self):
+ ynl_cfg(self.no_schema, self.spec, self.schema, self.json_text, self.ntf, self.sleep, self.do, self.dump)
+
+def ynl_cfg(no_schema, spec, schema, json_text, ntf, sleep, do, dump):
+
+ if no_schema:
+ schema = ''
+
+ attrs = {}
+ if json_text:
+ attrs = json.loads(json_text)
+
+ ynl = YnlFamily(spec, schema)
+
+ if ntf:
+ ynl.ntf_subscribe(ntf)
+
+ if sleep:
+ time.sleep(sleep)
+
+ if do:
+ reply = ynl.do(do, attrs)
+ pprint.PrettyPrinter().pprint(reply)
+ if dump:
+ reply = ynl.dump(dump, attrs)
+ pprint.PrettyPrinter().pprint(reply)
+
+ if ntf:
+ ynl.check_ntf()
+ pprint.PrettyPrinter().pprint(ynl.async_msg_queue)
def main():
parser = argparse.ArgumentParser(description='YNL CLI sample')
- parser.add_argument('--spec', dest='spec', type=str, required=True)
+ parser.add_argument('--spec', dest='spec', type=str)
parser.add_argument('--schema', dest='schema', type=str)
parser.add_argument('--no-schema', action='store_true')
parser.add_argument('--json', dest='json_text', type=str)
@@ -19,34 +60,59 @@ def main():
parser.add_argument('--dump', dest='dump', type=str)
parser.add_argument('--sleep', dest='sleep', type=int)
parser.add_argument('--subscribe', dest='ntf', type=str)
+ parser.add_argument('--config', dest='config', type=str)
args = parser.parse_args()
- if args.no_schema:
- args.schema = ''
-
- attrs = {}
- if args.json_text:
- attrs = json.loads(args.json_text)
+ if args.config:
+ directory = ""
+ yamls = {}
- ynl = YnlFamily(args.spec, args.schema)
+ if not os.path.exists(args.config):
+ print("Error: ", args.config, " doesn't exist")
+ exit(-1)
- if args.ntf:
- ynl.ntf_subscribe(args.ntf)
+ f = open(args.config)
+ data = json.load(f)
- if args.sleep:
- time.sleep(args.sleep)
+ for k in data:
+ if k == 'yaml-specs-path':
+ directory = data[k]
- if args.do:
- reply = ynl.do(args.do, attrs)
- pprint.PrettyPrinter().pprint(reply)
- if args.dump:
- reply = ynl.dump(args.dump, attrs)
- pprint.PrettyPrinter().pprint(reply)
+ # Scan the dir and get all the yaml files.
+ for filename in os.scandir(directory):
+ if filename.is_file():
+ if filename.name.endswith('.yaml'):
+ yamls[filename.name] = filename.path
- if args.ntf:
- ynl.check_ntf()
- pprint.PrettyPrinter().pprint(ynl.async_msg_queue)
+ elif k == 'spec-args':
+ for v in data[k]:
+ print("############### ",v," ###############\n")
+ cfg = ynlConfig()
+ # Check for yaml from the specs we found earlier
+ if v in yamls:
+ # FOUND
+ cfg.spec = yamls[v]
+ if 'no-schema' in data[k][v]:
+ cfg.no_schema = data[k][v]['no-schema']
+ if 'schema' in data[k][v]:
+ cfg.schema = data[k][v]['schema']
+ cfg.no_schema = False
+ if 'do' in data[k][v]:
+ cfg.do = data[k][v]['do']
+ if 'dump' in data[k][v]:
+ cfg.dump = data[k][v]['dump']
+ if 'subscribe' in data[k][v]:
+ cfg.ntf = data[k][v]['subscribe']
+ if 'sleep' in data[k][v]:
+ cfg.sleep = data[k][v]['sleep']
+ if 'json-params' in data[k][v]:
+ cfg.json_text = json.dumps(data[k][v]['json-params'])
+ cfg.run()
+ else:
+ print("Error: ", v, " doesn't have a valid yaml file in ", directory, "\n")
+ else:
+ ynl_cfg(args.no_schema, args.spec, args.schema, args.json_text, args.ntf, args.sleep, args.do, args.dump)
if __name__ == "__main__":
main()
--
2.41.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH net-next v2 2/2] tools/net/ynl: validate config against schema
2023-07-27 12:03 [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration Maryam Tahhan
2023-07-27 12:03 ` [PATCH net-next v2 1/2] tools/net/ynl: configuration through json Maryam Tahhan
@ 2023-07-27 12:03 ` Maryam Tahhan
2023-07-28 0:37 ` [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration Jakub Kicinski
2 siblings, 0 replies; 8+ messages in thread
From: Maryam Tahhan @ 2023-07-27 12:03 UTC (permalink / raw)
To: netdev; +Cc: kuba, davem, edumazet, pabeni, Maryam Tahhan, Keith Wiles
Validate the provided configuration file against
the ynl-config.schema.
Signed-off-by: Maryam Tahhan <mtahhan@redhat.com>
Signed-off-by: Keith Wiles <keith.wiles@intel.com>
Signed-off-by: Maryam Tahhan <mtahhan@redhat.com>
---
tools/net/ynl/cli.py | 43 ++++++++++++++++----
tools/net/ynl/ynl-config.schema | 72 +++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+), 7 deletions(-)
create mode 100644 tools/net/ynl/ynl-config.schema
diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py
index 1749851f8460..3071ef9e3117 100755
--- a/tools/net/ynl/cli.py
+++ b/tools/net/ynl/cli.py
@@ -9,6 +9,12 @@ import os
from lib import YnlFamily
+try:
+ import jsonschema
+except ModuleNotFoundError as e:
+ print('Error: {}. Try `pip install jsonschema`'.format(e))
+ raise SystemExit(1)
+
class ynlConfig():
def __init__(self):
self.no_schema = True
@@ -66,13 +72,36 @@ def main():
if args.config:
directory = ""
yamls = {}
-
- if not os.path.exists(args.config):
- print("Error: ", args.config, " doesn't exist")
- exit(-1)
-
- f = open(args.config)
- data = json.load(f)
+ configSchema = os.path.dirname(__file__) + "/ynl-config.schema"
+
+ # Load ynl-config json schema
+ try:
+ with open(configSchema, 'r') as f:
+ s = json.load(f)
+ except FileNotFoundError as e:
+ print('Error:', e)
+ raise SystemExit(1)
+ except json.decoder.JSONDecodeError as e:
+ print('Error: {}:'.format(args.schema), e)
+ raise SystemExit(1)
+
+ # Load config file
+ try:
+ with open(args.config, 'r') as f:
+ data = json.load(f)
+ except FileNotFoundError as e:
+ print('Error:', e)
+ raise SystemExit(1)
+ except json.decoder.JSONDecodeError as e:
+ print('Error: {}:'.format(args.schema), e)
+ raise SystemExit(1)
+
+ # Validate json config against the ynl-config schema
+ try:
+ jsonschema.validate(instance=data, schema=s)
+ except jsonschema.exceptions.ValidationError as e:
+ print('Error:', e)
+ raise SystemExit(1)
for k in data:
if k == 'yaml-specs-path':
diff --git a/tools/net/ynl/ynl-config.schema b/tools/net/ynl/ynl-config.schema
new file mode 100644
index 000000000000..c127e2acbabb
--- /dev/null
+++ b/tools/net/ynl/ynl-config.schema
@@ -0,0 +1,72 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "description": "YNL specs configuration file",
+ "type": "object",
+
+ "properties": {
+ "yaml-specs-path": {
+ "description": "Path to Yaml specs",
+ "type": "string"
+ },
+ "spec-args": {
+ "description": "Individual spec args",
+ "type": "object",
+ "patternProperties": {
+ "^.*(\\.yaml)$": {
+ "description": "Specific yaml spec arguments",
+ "type": "object",
+ "properties": {
+ "schema": {
+ "description": "The schema to use",
+ "type": "string"
+ },
+ "no-schema": {
+ "description": "No schema",
+ "type": "boolean",
+ "default": true
+ },
+ "do": {
+ "description": "The do function to use",
+ "type": "string"
+ },
+ "dump": {
+ "description": "The dump function to use",
+ "type": "string"
+ },
+ "subscribe": {
+ "description": "The multicast group to subscribe to",
+ "type": "string"
+ },
+ "sleep": {
+ "description": "The number to seconds to sleep",
+ "type": "number",
+ "default": 0
+ },
+ "json-params": {
+ "description": "The json params to use for different functions",
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "type": ["string", "number", "object"],
+ "patternProperties": {
+ "^.*$": {
+ "type": ["string", "number"]
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "yaml-specs-path"
+ ]
+}
--
2.41.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration
2023-07-27 12:03 [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration Maryam Tahhan
2023-07-27 12:03 ` [PATCH net-next v2 1/2] tools/net/ynl: configuration through json Maryam Tahhan
2023-07-27 12:03 ` [PATCH net-next v2 2/2] tools/net/ynl: validate config against schema Maryam Tahhan
@ 2023-07-28 0:37 ` Jakub Kicinski
2023-07-28 10:24 ` Maryam Tahhan
2 siblings, 1 reply; 8+ messages in thread
From: Jakub Kicinski @ 2023-07-28 0:37 UTC (permalink / raw)
To: Maryam Tahhan; +Cc: netdev, davem, edumazet, pabeni
On Thu, 27 Jul 2023 08:03:29 -0400 Maryam Tahhan wrote:
> Use a json configuration file to pass parameters to ynl to allow
> for operations on multiple specs in one go. Additionally, check
> this new configuration against a schema to validate it in the cli
> module before parsing it and passing info to the ynl module.
Interesting. Is this related to Donald's comments about subscribing
to notifications from multiple families?
Can you share some info about your use case?
> Example configs would be:
>
> {
> "yaml-specs-path": "/<path-to>/linux/Documentation/netlink/specs",
> "spec-args": {
> "ethtool.yaml": {
> "do": "rings-get",
> "json-params": {
> "header": {
> "dev-name": "eno1"
> }
> }
> },
> "netdev.yaml": {
> "do": "dev-get",
> "json-params": {
> "ifindex": 3
> }
> }
> }
> }
Why is the JSON preferable to writing a script to the same effect?
It'd actually be shorter and more flexible.
Maybe we should focus on packaging YNL as a python lib?
> OR
>
> {
> "yaml-specs-path": "/<path-to>/linux/Documentation/netlink/specs",
> "spec-args": {
> "ethtool.yaml": {
> "subscribe": "monitor",
> "sleep": 10
> },
> "netdev.yaml": {
> "subscribe": "mgmt",
> "sleep": 5
> }
> }
> }
Could you also share the outputs the examples would produce?
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration
2023-07-28 0:37 ` [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration Jakub Kicinski
@ 2023-07-28 10:24 ` Maryam Tahhan
2023-07-28 15:49 ` Jakub Kicinski
0 siblings, 1 reply; 8+ messages in thread
From: Maryam Tahhan @ 2023-07-28 10:24 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: netdev, davem, edumazet, pabeni
On 28/07/2023 01:37, Jakub Kicinski wrote:
> On Thu, 27 Jul 2023 08:03:29 -0400 Maryam Tahhan wrote:
>> Use a json configuration file to pass parameters to ynl to allow
>> for operations on multiple specs in one go. Additionally, check
>> this new configuration against a schema to validate it in the cli
>> module before parsing it and passing info to the ynl module.
> Interesting. Is this related to Donald's comments about subscribing
> to notifications from multiple families?
>
> Can you share some info about your use case?
Yes it's related. We are working towards using YNL as a netlink agent or
part of a netlink agent that's driven by YAML specs. We are
trying to enable existing Kubernetes CNIs to integrate with DPUs via an
OPI [1] API without having to change these existing CNIs. In several
cases these CNIs program the Kernel as both the control plane and the
fallback dataplane (for packets the DPU accelerator doesn't know what
to do with). And so being able to monitor netlink state and reflect it
to the DPU accelerator (and vice versa) via an OPI API would be
extremely useful.
We think the YAML part gives us a solid model that showcases the breadth
of what these CNIs program (via netlink) as well as a base for the grpc
protobufs that
the OPI API would like to define/use.
>> Example configs would be:
>>
>> {
>> "yaml-specs-path": "/<path-to>/linux/Documentation/netlink/specs",
>> "spec-args": {
>> "ethtool.yaml": {
>> "do": "rings-get",
>> "json-params": {
>> "header": {
>> "dev-name": "eno1"
>> }
>> }
>> },
>> "netdev.yaml": {
>> "do": "dev-get",
>> "json-params": {
>> "ifindex": 3
>> }
>> }
>> }
>> }
> Why is the JSON preferable to writing a script to the same effect?
> It'd actually be shorter and more flexible.
> Maybe we should focus on packaging YNL as a python lib?
I guess you can write a script. The reasons I picked JSON were mainly:
- Simplicity and Readability for both developers and non-developers/users.
- With the JSON Schema Validation I could very quickly validate the
incoming configuration without too much logic in cli.py.
- I thought of it as a stepping stone towards an agent configuration
file if YNL evolves to provide or be part of a netlink agent (driven by
yaml specs)...
>
>> OR
>>
>> {
>> "yaml-specs-path": "/<path-to>/linux/Documentation/netlink/specs",
>> "spec-args": {
>> "ethtool.yaml": {
>> "subscribe": "monitor",
>> "sleep": 10
>> },
>> "netdev.yaml": {
>> "subscribe": "mgmt",
>> "sleep": 5
>> }
>> }
>> }
> Could you also share the outputs the examples would produce?
>
Right now the output is simple, an example would be for the first config
in the email:
[ linux]# ./tools/net/ynl/cli.py --config ./tools/net/ynl/multi-do.json
############### ethtool.yaml ###############
{'header': {'dev-index': 3, 'dev-name': 'eno1'},
'rx': 512,
'rx-max': 8192,
'rx-push': 0,
'tx': 512,
'tx-max': 8192,
'tx-push': 0}
############### netdev.yaml ###############
{'ifindex': 3, 'xdp-features': {'xsk-zerocopy', 'redirect', 'basic'}}
Or for the second config in the email (note: I just toggled the tx ring
descriptors on one of my NICs to trigger an ethtool notification):
[root@nfvsdn-06 linux]# ./tools/net/ynl/cli.py --config
./tools/net/ynl/multi-ntf.json
############### ethtool.yaml ###############
[{'msg': {'header': {'dev-index': 3, 'dev-name': 'eno1'},
'rx': 512,
'rx-max': 8192,
'rx-push': 0,
'tx': 8192,
'tx-max': 8192,
'tx-push': 0},
'name': 'rings-ntf'}]
############### netdev.yaml ###############
[]
At the moment (even with these changes) YNL subscribes-sleeps-checks for
notification for each family sequentially...
I will be looking into enabling an agent like behaviour: subscribe to
notifications from multiple families and monitor (babysteps)....
[1] https://opiproject.org/
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration
2023-07-28 10:24 ` Maryam Tahhan
@ 2023-07-28 15:49 ` Jakub Kicinski
2023-07-31 8:12 ` Maryam Tahhan
0 siblings, 1 reply; 8+ messages in thread
From: Jakub Kicinski @ 2023-07-28 15:49 UTC (permalink / raw)
To: Maryam Tahhan; +Cc: netdev, davem, edumazet, pabeni
On Fri, 28 Jul 2023 11:24:51 +0100 Maryam Tahhan wrote:
> On 28/07/2023 01:37, Jakub Kicinski wrote:
> > On Thu, 27 Jul 2023 08:03:29 -0400 Maryam Tahhan wrote:
> >> Use a json configuration file to pass parameters to ynl to allow
> >> for operations on multiple specs in one go. Additionally, check
> >> this new configuration against a schema to validate it in the cli
> >> module before parsing it and passing info to the ynl module.
> > Interesting. Is this related to Donald's comments about subscribing
> > to notifications from multiple families?
> >
> > Can you share some info about your use case?
>
>
> Yes it's related. We are working towards using YNL as a netlink agent or
> part of a netlink agent that's driven by YAML specs. We are
>
> trying to enable existing Kubernetes CNIs to integrate with DPUs via an
> OPI [1] API without having to change these existing CNIs. In several
>
> cases these CNIs program the Kernel as both the control plane and the
> fallback dataplane (for packets the DPU accelerator doesn't know what
> to do with). And so being able to monitor netlink state and reflect it
> to the DPU accelerator (and vice versa) via an OPI API would be
> extremely useful.
>
>
> We think the YAML part gives us a solid model that showcases the breadth
> of what these CNIs program (via netlink) as well as a base for the grpc
> protobufs that the OPI API would like to define/use.
So agent on the host is listening to netlink and sending to DPU gRPC
requests? From what you're describing it sounds like you'd mostly want
to pass the notifications. The multi-command thing is to let the DPU
also make requests if it needs to do/know something specific?
> >> Example configs would be:
> >>
> >> {
> >> "yaml-specs-path": "/<path-to>/linux/Documentation/netlink/specs",
> >> "spec-args": {
> >> "ethtool.yaml": {
> >> "do": "rings-get",
> >> "json-params": {
> >> "header": {
> >> "dev-name": "eno1"
> >> }
> >> }
> >> },
> >> "netdev.yaml": {
> >> "do": "dev-get",
> >> "json-params": {
> >> "ifindex": 3
> >> }
> >> }
> >> }
> >> }
> > Why is the JSON preferable to writing a script to the same effect?
> > It'd actually be shorter and more flexible.
> > Maybe we should focus on packaging YNL as a python lib?
>
> I guess you can write a script. The reasons I picked JSON were mainly:
>
> - Simplicity and Readability for both developers and non-developers/users.
>
> - With the JSON Schema Validation I could very quickly validate the
> incoming configuration without too much logic in cli.py.
>
> - I thought of it as a stepping stone towards an agent configuration
> file if YNL evolves to provide or be part of a netlink agent (driven by
> yaml specs)...
Those are very valid. My worry is that:
- it's not a great fit for asynchronous stuff like notifications
(at least a simple version built directly from cli.py)
- we'd end up needing some flow control and/or transfer of values
at some point, and it will evolve into a full blown DSL
> >> OR
> >>
> >> {
> >> "yaml-specs-path": "/<path-to>/linux/Documentation/netlink/specs",
> >> "spec-args": {
> >> "ethtool.yaml": {
> >> "subscribe": "monitor",
> >> "sleep": 10
> >> },
> >> "netdev.yaml": {
> >> "subscribe": "mgmt",
> >> "sleep": 5
> >> }
> >> }
> >> }
> > Could you also share the outputs the examples would produce?
> >
> Right now the output is simple, an example would be for the first config
> in the email:
>
> [ linux]# ./tools/net/ynl/cli.py --config ./tools/net/ynl/multi-do.json
> ############### ethtool.yaml ###############
>
> {'header': {'dev-index': 3, 'dev-name': 'eno1'},
> 'rx': 512,
> 'rx-max': 8192,
> 'rx-push': 0,
> 'tx': 512,
> 'tx-max': 8192,
> 'tx-push': 0}
> ############### netdev.yaml ###############
>
> {'ifindex': 3, 'xdp-features': {'xsk-zerocopy', 'redirect', 'basic'}}
My concern was that this will not be optimal for the receiver to parse.
Because the answer is not valid JSON. We'd need something like:
[
{ "cmd-id": "some-identifier?".
"response": { ... }
},
{ "cmd-id": "identifier-of-second-command".
"response": { ... }
}
]
> Or for the second config in the email (note: I just toggled the tx ring
> descriptors on one of my NICs to trigger an ethtool notification):
>
> [root@nfvsdn-06 linux]# ./tools/net/ynl/cli.py --config
> ./tools/net/ynl/multi-ntf.json
> ############### ethtool.yaml ###############
>
> [{'msg': {'header': {'dev-index': 3, 'dev-name': 'eno1'},
> 'rx': 512,
> 'rx-max': 8192,
> 'rx-push': 0,
> 'tx': 8192,
> 'tx-max': 8192,
> 'tx-push': 0},
> 'name': 'rings-ntf'}]
> ############### netdev.yaml ###############
>
> []
>
> At the moment (even with these changes) YNL subscribes-sleeps-checks for
> notification for each family sequentially...
> I will be looking into enabling an agent like behaviour: subscribe to
> notifications from multiple families and monitor (babysteps)....
>
> [1] https://opiproject.org/
Modulo the nits it sounds fairly reasonable. Main question is how much
of that we put in the kernel tree, and how much lives elsewhere :S
If we have a dependency on gRPC at some point, for example, that may
be too much for kernel tools/
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH net-next v2 0/2] tools/net/ynl: enable json configuration
2023-07-28 15:49 ` Jakub Kicinski
@ 2023-07-31 8:12 ` Maryam Tahhan
0 siblings, 0 replies; 8+ messages in thread
From: Maryam Tahhan @ 2023-07-31 8:12 UTC (permalink / raw)
To: Jakub Kicinski
Cc: netdev, davem, edumazet, pabeni, Donald Hunter, Billy McFall
On 28/07/2023 16:49, Jakub Kicinski wrote:
> On Fri, 28 Jul 2023 11:24:51 +0100 Maryam Tahhan wrote:
>> On 28/07/2023 01:37, Jakub Kicinski wrote:
>>> On Thu, 27 Jul 2023 08:03:29 -0400 Maryam Tahhan wrote:
>>>> Use a json configuration file to pass parameters to ynl to allow
>>>> for operations on multiple specs in one go. Additionally, check
>>>> this new configuration against a schema to validate it in the cli
>>>> module before parsing it and passing info to the ynl module.
>>> Interesting. Is this related to Donald's comments about subscribing
>>> to notifications from multiple families?
>>>
>>> Can you share some info about your use case?
>>
>> Yes it's related. We are working towards using YNL as a netlink agent or
>> part of a netlink agent that's driven by YAML specs. We are
>>
>> trying to enable existing Kubernetes CNIs to integrate with DPUs via an
>> OPI [1] API without having to change these existing CNIs. In several
>>
>> cases these CNIs program the Kernel as both the control plane and the
>> fallback dataplane (for packets the DPU accelerator doesn't know what
>> to do with). And so being able to monitor netlink state and reflect it
>> to the DPU accelerator (and vice versa) via an OPI API would be
>> extremely useful.
>>
>>
>> We think the YAML part gives us a solid model that showcases the breadth
>> of what these CNIs program (via netlink) as well as a base for the grpc
>> protobufs that the OPI API would like to define/use.
> So agent on the host is listening to netlink and sending to DPU gRPC
> requests? From what you're describing it sounds like you'd mostly want
> to pass the notifications. The multi-command thing is to let the DPU
> also make requests if it needs to do/know something specific?
Yes, this is pretty much the idea.
>
>>>> Example configs would be:
>>>>
>>>> {
>>>> "yaml-specs-path": "/<path-to>/linux/Documentation/netlink/specs",
>>>> "spec-args": {
>>>> "ethtool.yaml": {
>>>> "do": "rings-get",
>>>> "json-params": {
>>>> "header": {
>>>> "dev-name": "eno1"
>>>> }
>>>> }
>>>> },
>>>> "netdev.yaml": {
>>>> "do": "dev-get",
>>>> "json-params": {
>>>> "ifindex": 3
>>>> }
>>>> }
>>>> }
>>>> }
>>> Why is the JSON preferable to writing a script to the same effect?
>>> It'd actually be shorter and more flexible.
>>> Maybe we should focus on packaging YNL as a python lib?
>> I guess you can write a script. The reasons I picked JSON were mainly:
>>
>> - Simplicity and Readability for both developers and non-developers/users.
>>
>> - With the JSON Schema Validation I could very quickly validate the
>> incoming configuration without too much logic in cli.py.
>>
>> - I thought of it as a stepping stone towards an agent configuration
>> file if YNL evolves to provide or be part of a netlink agent (driven by
>> yaml specs)...
> Those are very valid. My worry is that:
> - it's not a great fit for asynchronous stuff like notifications
> (at least a simple version built directly from cli.py)
> - we'd end up needing some flow control and/or transfer of values
> at some point, and it will evolve into a full blown DSL
Ok, I can look at a script and see what this looks like.
>
>>>> OR
>>>>
>>>> {
>>>> "yaml-specs-path": "/<path-to>/linux/Documentation/netlink/specs",
>>>> "spec-args": {
>>>> "ethtool.yaml": {
>>>> "subscribe": "monitor",
>>>> "sleep": 10
>>>> },
>>>> "netdev.yaml": {
>>>> "subscribe": "mgmt",
>>>> "sleep": 5
>>>> }
>>>> }
>>>> }
>>> Could you also share the outputs the examples would produce?
>>>
>> Right now the output is simple, an example would be for the first config
>> in the email:
>>
>> [ linux]# ./tools/net/ynl/cli.py --config ./tools/net/ynl/multi-do.json
>> ############### ethtool.yaml ###############
>>
>> {'header': {'dev-index': 3, 'dev-name': 'eno1'},
>> 'rx': 512,
>> 'rx-max': 8192,
>> 'rx-push': 0,
>> 'tx': 512,
>> 'tx-max': 8192,
>> 'tx-push': 0}
>> ############### netdev.yaml ###############
>>
>> {'ifindex': 3, 'xdp-features': {'xsk-zerocopy', 'redirect', 'basic'}}
> My concern was that this will not be optimal for the receiver to parse.
> Because the answer is not valid JSON. We'd need something like:
>
> [
> { "cmd-id": "some-identifier?".
> "response": { ... }
> },
> { "cmd-id": "identifier-of-second-command".
> "response": { ... }
> }
> ]
>
Yeah - makes sense. I was only focused on the configuration part for
this patchset. This can be added.
>> Or for the second config in the email (note: I just toggled the tx ring
>> descriptors on one of my NICs to trigger an ethtool notification):
>>
>> [root@nfvsdn-06 linux]# ./tools/net/ynl/cli.py --config
>> ./tools/net/ynl/multi-ntf.json
>> ############### ethtool.yaml ###############
>>
>> [{'msg': {'header': {'dev-index': 3, 'dev-name': 'eno1'},
>> 'rx': 512,
>> 'rx-max': 8192,
>> 'rx-push': 0,
>> 'tx': 8192,
>> 'tx-max': 8192,
>> 'tx-push': 0},
>> 'name': 'rings-ntf'}]
>> ############### netdev.yaml ###############
>>
>> []
>>
>> At the moment (even with these changes) YNL subscribes-sleeps-checks for
>> notification for each family sequentially...
>> I will be looking into enabling an agent like behaviour: subscribe to
>> notifications from multiple families and monitor (babysteps)....
>>
>> [1] https://opiproject.org/
> Modulo the nits it sounds fairly reasonable. Main question is how much
> of that we put in the kernel tree, and how much lives elsewhere :S
> If we have a dependency on gRPC at some point, for example, that may
> be too much for kernel tools/
Yeah, that's a fair question. We would like to get all the gRPC stuff
into the OPI repos. In the Kernel tree we'd like to get the netlink
agent and the YAML specs.
Thanks for the feedback. I will take it onboard.
>
^ permalink raw reply [flat|nested] 8+ messages in thread