Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'tools-ynl-gen-support-sub-messages-and-rt-link'

Jakub Kicinski says:

====================
tools: ynl-gen: support sub-messages and rt-link

Sub-messages are how we express "polymorphism" in YNL. Donald added
the support to specs and Python a while back, support them in C, too.
Sub-message is a nest, but the interpretation of the attribute types
within that nest depends on a value of another attribute. For example
in rt-link the "kind" attribute contains the link type (veth, bonding,
etc.) and based on that the right enum has to be applied to interpret
link-specific attributes.

The last message is probably the most interesting to look at, as it
adds a fairly advanced sample.

This patch only contains enough support for rtnetlink, we will need
a little more complexity to support TC, where sub-messages may contain
fixed headers, and where the selector may be in a different nest than
the submessage.
====================

Link: https://patch.msgid.link/20250515231650.1325372-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+517 -62
+4
Documentation/netlink/specs/rt-link.yaml
··· 594 594 name: reasm-overlaps 595 595 - name: br-boolopt-multi 596 596 type: struct 597 + header: linux/if_bridge.h 597 598 members: 598 599 - 599 600 name: optval ··· 827 826 - name: default 828 827 - 829 828 name: ovpn-mode 829 + enum-name: ovpn-mode 830 + name-prefix: ovpn-mode 830 831 type: enum 831 832 entries: 832 833 - p2p ··· 2198 2195 type: u16 2199 2196 - 2200 2197 name: linkinfo-ovpn-attrs 2198 + name-prefix: ifla-ovpn- 2201 2199 attributes: 2202 2200 - 2203 2201 name: mode
+4
tools/net/ynl/Makefile.deps
··· 33 33 CFLAGS_ovs_vport:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) 34 34 CFLAGS_rt-addr:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) \ 35 35 $(call get_hdr_inc,__LINUX_IF_ADDR_H,if_addr.h) 36 + CFLAGS_rt-link:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) \ 37 + $(call get_hdr_inc,_LINUX_IF_LINK_H,if_link.h) 38 + CFLAGS_rt-neigh:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) 36 39 CFLAGS_rt-route:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) 40 + CFLAGS_rt-rule:=$(call get_hdr_inc,__LINUX_FIB_RULES_H,fib_rules.h) 37 41 CFLAGS_tcp_metrics:=$(call get_hdr_inc,_LINUX_TCP_METRICS_H,tcp_metrics.h)
+3 -4
tools/net/ynl/generated/Makefile
··· 22 22 TOOL_RST:=../pyynl/ynl_gen_rst.py 23 23 24 24 SPECS_DIR:=../../../../Documentation/netlink/specs 25 - GENS_PATHS=$(shell grep -nrI --files-without-match \ 26 - 'protocol: netlink' \ 27 - $(SPECS_DIR)) 28 - GENS=$(patsubst $(SPECS_DIR)/%.yaml,%,${GENS_PATHS}) rt-addr rt-route 25 + SPECS_PATHS=$(wildcard $(SPECS_DIR)/*.yaml) 26 + GENS_UNSUP=conntrack nftables tc 27 + GENS=$(filter-out ${GENS_UNSUP},$(patsubst $(SPECS_DIR)/%.yaml,%,${SPECS_PATHS})) 29 28 SRCS=$(patsubst %,%-user.c,${GENS}) 30 29 HDRS=$(patsubst %,%-user.h,${GENS}) 31 30 OBJS=$(patsubst %,%-user.o,${GENS})
+7 -1
tools/net/ynl/lib/ynl-priv.h
··· 25 25 YNL_PT_UINT, 26 26 YNL_PT_NUL_STR, 27 27 YNL_PT_BITFIELD32, 28 + YNL_PT_SUBMSG, 28 29 }; 29 30 30 31 enum ynl_parse_result { ··· 43 42 struct ynl_parse_arg *yarg); 44 43 45 44 struct ynl_policy_attr { 46 - enum ynl_policy_type type; 45 + enum ynl_policy_type type:8; 46 + __u8 is_submsg:1; 47 + __u8 is_selector:1; 48 + __u16 selector_type; 47 49 unsigned int len; 48 50 const char *name; 49 51 const struct ynl_policy_nest *nest; ··· 107 103 ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); 108 104 109 105 int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); 106 + int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, 107 + const char *sel_name); 110 108 111 109 /* YNL specific helpers used by the auto-generated code */ 112 110
+84 -9
tools/net/ynl/lib/ynl.c
··· 45 45 #define perr(_ys, _msg) __yerr(&(_ys)->err, errno, _msg) 46 46 47 47 /* -- Netlink boiler plate */ 48 + static bool 49 + ynl_err_walk_is_sel(const struct ynl_policy_nest *policy, 50 + const struct nlattr *attr) 51 + { 52 + unsigned int type = ynl_attr_type(attr); 53 + 54 + return policy && type <= policy->max_attr && 55 + policy->table[type].is_selector; 56 + } 57 + 58 + static const struct ynl_policy_nest * 59 + ynl_err_walk_sel_policy(const struct ynl_policy_attr *policy_attr, 60 + const struct nlattr *selector) 61 + { 62 + const struct ynl_policy_nest *policy = policy_attr->nest; 63 + const char *sel; 64 + unsigned int i; 65 + 66 + if (!policy_attr->is_submsg) 67 + return policy; 68 + 69 + sel = ynl_attr_get_str(selector); 70 + for (i = 0; i <= policy->max_attr; i++) { 71 + if (!strcmp(sel, policy->table[i].name)) 72 + return policy->table[i].nest; 73 + } 74 + 75 + return NULL; 76 + } 77 + 48 78 static int 49 - ynl_err_walk_report_one(const struct ynl_policy_nest *policy, unsigned int type, 79 + ynl_err_walk_report_one(const struct ynl_policy_nest *policy, 80 + const struct nlattr *selector, unsigned int type, 50 81 char *str, int str_sz, int *n) 51 82 { 52 83 if (!policy) { ··· 98 67 return 1; 99 68 } 100 69 101 - if (*n < str_sz) 102 - *n += snprintf(str, str_sz - *n, 103 - ".%s", policy->table[type].name); 70 + if (*n < str_sz) { 71 + int sz; 72 + 73 + sz = snprintf(str, str_sz - *n, 74 + ".%s", policy->table[type].name); 75 + *n += sz; 76 + str += sz; 77 + } 78 + 79 + if (policy->table[type].is_submsg) { 80 + if (!selector) { 81 + if (*n < str_sz) 82 + *n += snprintf(str, str_sz, "(!selector)"); 83 + return 1; 84 + } 85 + 86 + if (ynl_attr_type(selector) != 87 + policy->table[type].selector_type) { 88 + if (*n < str_sz) 89 + *n += snprintf(str, str_sz, "(!=selector)"); 90 + return 1; 91 + } 92 + 93 + if (*n < str_sz) 94 + *n += snprintf(str, str_sz - *n, "(%s)", 95 + ynl_attr_get_str(selector)); 96 + } 97 + 104 98 return 0; 105 99 } 106 100 ··· 134 78 const struct ynl_policy_nest *policy, char *str, int str_sz, 135 79 const struct ynl_policy_nest **nest_pol) 136 80 { 81 + const struct ynl_policy_nest *next_pol; 82 + const struct nlattr *selector = NULL; 137 83 unsigned int astart_off, aend_off; 138 84 const struct nlattr *attr; 139 85 unsigned int data_len; ··· 154 96 ynl_attr_for_each_payload(start, data_len, attr) { 155 97 astart_off = (char *)attr - (char *)start; 156 98 aend_off = (char *)ynl_attr_data_end(attr) - (char *)start; 99 + 100 + if (ynl_err_walk_is_sel(policy, attr)) 101 + selector = attr; 102 + 157 103 if (aend_off <= off) 158 104 continue; 159 105 ··· 171 109 172 110 type = ynl_attr_type(attr); 173 111 174 - if (ynl_err_walk_report_one(policy, type, str, str_sz, &n)) 112 + if (ynl_err_walk_report_one(policy, selector, type, str, str_sz, &n)) 113 + return n; 114 + 115 + next_pol = ynl_err_walk_sel_policy(&policy->table[type], selector); 116 + if (!next_pol) 175 117 return n; 176 118 177 119 if (!off) { 178 120 if (nest_pol) 179 - *nest_pol = policy->table[type].nest; 121 + *nest_pol = next_pol; 180 122 return n; 181 123 } 182 124 183 - if (!policy->table[type].nest) { 125 + if (!next_pol) { 184 126 if (n < str_sz) 185 127 n += snprintf(str, str_sz, "!nest"); 186 128 return n; ··· 194 128 start = ynl_attr_data(attr); 195 129 end = start + ynl_attr_data_len(attr); 196 130 197 - return n + ynl_err_walk(ys, start, end, off, policy->table[type].nest, 131 + return n + ynl_err_walk(ys, start, end, off, next_pol, 198 132 &str[n], str_sz - n, nest_pol); 199 133 } 200 134 ··· 297 231 } 298 232 299 233 n2 = 0; 300 - ynl_err_walk_report_one(nest_pol, type, &miss_attr[n], 234 + ynl_err_walk_report_one(nest_pol, NULL, type, &miss_attr[n], 301 235 sizeof(miss_attr) - n, &n2); 302 236 n += n2; 303 237 ··· 448 382 } 449 383 450 384 return 0; 385 + } 386 + 387 + int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, 388 + const char *sel_name) 389 + { 390 + yerr(yarg->ys, YNL_ERROR_SUBMSG_KEY, 391 + "Parsing error: Sub-message key not set (msg %s, key %s)", 392 + field_name, sel_name); 393 + return YNL_PARSE_CB_ERROR; 451 394 } 452 395 453 396 /* Generic code */
+1
tools/net/ynl/lib/ynl.h
··· 23 23 YNL_ERROR_INV_RESP, 24 24 YNL_ERROR_INPUT_INVALID, 25 25 YNL_ERROR_INPUT_TOO_BIG, 26 + YNL_ERROR_SUBMSG_KEY, 26 27 }; 27 28 28 29 /**
+3 -2
tools/net/ynl/pyynl/lib/__init__.py
··· 1 1 # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 2 3 3 from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \ 4 - SpecFamily, SpecOperation 4 + SpecFamily, SpecOperation, SpecSubMessage, SpecSubMessageFormat 5 5 from .ynl import YnlFamily, Netlink, NlError 6 6 7 7 __all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet", 8 - "SpecFamily", "SpecOperation", "YnlFamily", "Netlink", "NlError"] 8 + "SpecFamily", "SpecOperation", "SpecSubMessage", "SpecSubMessageFormat", 9 + "YnlFamily", "Netlink", "NlError"]
+226 -46
tools/net/ynl/pyynl/ynl_gen_c.py
··· 14 14 15 15 sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) 16 16 from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry 17 + from lib import SpecSubMessage, SpecSubMessageFormat 17 18 18 19 19 20 def c_upper(name): ··· 57 56 self.request = False 58 57 self.reply = False 59 58 59 + self.is_selector = False 60 + 60 61 if 'len' in attr: 61 62 self.len = attr['len'] 62 63 63 64 if 'nested-attributes' in attr: 64 - self.nested_attrs = attr['nested-attributes'] 65 + nested = attr['nested-attributes'] 66 + elif 'sub-message' in attr: 67 + nested = attr['sub-message'] 68 + else: 69 + nested = None 70 + 71 + if nested: 72 + self.nested_attrs = nested 65 73 if self.nested_attrs == family.name: 66 74 self.nested_render_name = c_lower(f"{family.ident_name}") 67 75 else: ··· 129 119 return c_upper(value) 130 120 131 121 def resolve(self): 132 - if 'name-prefix' in self.attr: 122 + if 'parent-sub-message' in self.attr: 123 + enum_name = self.attr['parent-sub-message'].enum_name 124 + elif 'name-prefix' in self.attr: 133 125 enum_name = f"{self.attr['name-prefix']}{self.name}" 134 126 else: 135 127 enum_name = f"{self.attr_set.name_prefix}{self.name}" ··· 486 474 ri.cw.p(f"char *{self.c_name};") 487 475 488 476 def _attr_typol(self): 489 - return f'.type = YNL_PT_NUL_STR, ' 477 + typol = f'.type = YNL_PT_NUL_STR, ' 478 + if self.is_selector: 479 + typol += '.is_selector = 1, ' 480 + return typol 490 481 491 482 def _attr_policy(self, policy): 492 483 if 'exact-len' in self.checks: ··· 882 867 return get_lines, init_lines, local_vars 883 868 884 869 870 + class TypeSubMessage(TypeNest): 871 + def __init__(self, family, attr_set, attr, value): 872 + super().__init__(family, attr_set, attr, value) 873 + 874 + self.selector = Selector(attr, attr_set) 875 + 876 + def _attr_typol(self): 877 + typol = f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' 878 + typol += f'.is_submsg = 1, .selector_type = {self.attr_set[self["selector"]].value} ' 879 + return typol 880 + 881 + def _attr_get(self, ri, var): 882 + sel = c_lower(self['selector']) 883 + get_lines = [f'if (!{var}->{sel})', 884 + f'return ynl_submsg_failed(yarg, "%s", "%s");' % 885 + (self.name, self['selector']), 886 + f"if ({self.nested_render_name}_parse(&parg, {var}->{sel}, attr))", 887 + "return YNL_PARSE_CB_ERROR;"] 888 + init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;", 889 + f"parg.data = &{var}->{self.c_name};"] 890 + return get_lines, init_lines, None 891 + 892 + 893 + class Selector: 894 + def __init__(self, msg_attr, attr_set): 895 + self.name = msg_attr["selector"] 896 + 897 + if self.name in attr_set: 898 + self.attr = attr_set[self.name] 899 + self.attr.is_selector = True 900 + self._external = False 901 + else: 902 + raise Exception("Passing selectors from external nests not supported") 903 + 904 + 885 905 class Struct: 886 - def __init__(self, family, space_name, type_list=None, inherited=None): 906 + def __init__(self, family, space_name, type_list=None, 907 + inherited=None, submsg=None): 887 908 self.family = family 888 909 self.space_name = space_name 889 910 self.attr_set = family.attr_sets[space_name] 890 911 # Use list to catch comparisons with empty sets 891 912 self._inherited = inherited if inherited is not None else [] 892 913 self.inherited = [] 914 + self.submsg = submsg 893 915 894 916 self.nested = type_list is None 895 917 if family.name == c_lower(space_name): ··· 1099 1047 raise Exception(f'new_attr: unsupported sub-type {elem["sub-type"]}') 1100 1048 elif elem['type'] == 'nest-type-value': 1101 1049 t = TypeNestTypeValue(self.family, self, elem, value) 1050 + elif elem['type'] == 'sub-message': 1051 + t = TypeSubMessage(self.family, self, elem, value) 1102 1052 else: 1103 1053 raise Exception(f"No typed class for type {elem['type']}") 1104 1054 ··· 1143 1089 1144 1090 def mark_has_ntf(self): 1145 1091 self.has_ntf = True 1092 + 1093 + 1094 + class SubMessage(SpecSubMessage): 1095 + def __init__(self, family, yaml): 1096 + super().__init__(family, yaml) 1097 + 1098 + self.render_name = c_lower(family.ident_name + '-' + yaml['name']) 1099 + 1100 + def resolve(self): 1101 + self.resolve_up(super()) 1146 1102 1147 1103 1148 1104 class Family(SpecFamily): ··· 1237 1173 def new_operation(self, elem, req_value, rsp_value): 1238 1174 return Operation(self, elem, req_value, rsp_value) 1239 1175 1176 + def new_sub_message(self, elem): 1177 + return SubMessage(self, elem) 1178 + 1240 1179 def is_classic(self): 1241 1180 return self.proto == 'netlink-raw' 1242 1181 ··· 1292 1225 for _, spec in self.attr_sets[name].items(): 1293 1226 if 'nested-attributes' in spec: 1294 1227 nested = spec['nested-attributes'] 1295 - # If the unknown nest we hit is recursive it's fine, it'll be a pointer 1296 - if self.pure_nested_structs[nested].recursive: 1297 - continue 1298 - if nested not in pns_key_seen: 1299 - # Dicts are sorted, this will make struct last 1300 - struct = self.pure_nested_structs.pop(name) 1301 - self.pure_nested_structs[name] = struct 1302 - finished = False 1303 - break 1228 + elif 'sub-message' in spec: 1229 + nested = spec.sub_message 1230 + else: 1231 + continue 1232 + 1233 + # If the unknown nest we hit is recursive it's fine, it'll be a pointer 1234 + if self.pure_nested_structs[nested].recursive: 1235 + continue 1236 + if nested not in pns_key_seen: 1237 + # Dicts are sorted, this will make struct last 1238 + struct = self.pure_nested_structs.pop(name) 1239 + self.pure_nested_structs[name] = struct 1240 + finished = False 1241 + break 1304 1242 if finished: 1305 1243 pns_key_seen.add(name) 1306 1244 else: 1307 1245 pns_key_list.append(name) 1246 + 1247 + def _load_nested_set_nest(self, spec): 1248 + inherit = set() 1249 + nested = spec['nested-attributes'] 1250 + if nested not in self.root_sets: 1251 + if nested not in self.pure_nested_structs: 1252 + self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) 1253 + else: 1254 + raise Exception(f'Using attr set as root and nested not supported - {nested}') 1255 + 1256 + if 'type-value' in spec: 1257 + if nested in self.root_sets: 1258 + raise Exception("Inheriting members to a space used as root not supported") 1259 + inherit.update(set(spec['type-value'])) 1260 + elif spec['type'] == 'indexed-array': 1261 + inherit.add('idx') 1262 + self.pure_nested_structs[nested].set_inherited(inherit) 1263 + 1264 + return nested 1265 + 1266 + def _load_nested_set_submsg(self, spec): 1267 + # Fake the struct type for the sub-message itself 1268 + # its not a attr_set but codegen wants attr_sets. 1269 + submsg = self.sub_msgs[spec["sub-message"]] 1270 + nested = submsg.name 1271 + 1272 + attrs = [] 1273 + for name, fmt in submsg.formats.items(): 1274 + attrs.append({ 1275 + "name": name, 1276 + "type": "nest", 1277 + "parent-sub-message": spec, 1278 + "nested-attributes": fmt['attribute-set'] 1279 + }) 1280 + 1281 + self.attr_sets[nested] = AttrSet(self, { 1282 + "name": nested, 1283 + "name-pfx": self.name + '-' + spec.name + '-', 1284 + "attributes": attrs 1285 + }) 1286 + 1287 + if nested not in self.pure_nested_structs: 1288 + self.pure_nested_structs[nested] = Struct(self, nested, submsg=submsg) 1289 + 1290 + return nested 1308 1291 1309 1292 def _load_nested_sets(self): 1310 1293 attr_set_queue = list(self.root_sets.keys()) ··· 1363 1246 while len(attr_set_queue): 1364 1247 a_set = attr_set_queue.pop(0) 1365 1248 for attr, spec in self.attr_sets[a_set].items(): 1366 - if 'nested-attributes' not in spec: 1249 + if 'nested-attributes' in spec: 1250 + nested = self._load_nested_set_nest(spec) 1251 + elif 'sub-message' in spec: 1252 + nested = self._load_nested_set_submsg(spec) 1253 + else: 1367 1254 continue 1368 1255 1369 - nested = spec['nested-attributes'] 1370 1256 if nested not in attr_set_seen: 1371 1257 attr_set_queue.append(nested) 1372 1258 attr_set_seen.add(nested) 1373 - 1374 - inherit = set() 1375 - if nested not in self.root_sets: 1376 - if nested not in self.pure_nested_structs: 1377 - self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) 1378 - else: 1379 - raise Exception(f'Using attr set as root and nested not supported - {nested}') 1380 - 1381 - if 'type-value' in spec: 1382 - if nested in self.root_sets: 1383 - raise Exception("Inheriting members to a space used as root not supported") 1384 - inherit.update(set(spec['type-value'])) 1385 - elif spec['type'] == 'indexed-array': 1386 - inherit.add('idx') 1387 - self.pure_nested_structs[nested].set_inherited(inherit) 1388 1259 1389 1260 for root_set, rs_members in self.root_sets.items(): 1390 1261 for attr, spec in self.attr_sets[root_set].items(): 1391 1262 if 'nested-attributes' in spec: 1392 1263 nested = spec['nested-attributes'] 1264 + elif 'sub-message' in spec: 1265 + nested = spec.sub_message 1266 + else: 1267 + nested = None 1268 + 1269 + if nested: 1393 1270 if attr in rs_members['request']: 1394 1271 self.pure_nested_structs[nested].request = True 1395 1272 if attr in rs_members['reply']: 1396 1273 self.pure_nested_structs[nested].reply = True 1274 + 1397 1275 if spec.is_multi_val(): 1398 1276 child = self.pure_nested_structs.get(nested) 1399 1277 child.in_multi_val = True ··· 1398 1286 # Propagate the request / reply / recursive 1399 1287 for attr_set, struct in reversed(self.pure_nested_structs.items()): 1400 1288 for _, spec in self.attr_sets[attr_set].items(): 1401 - if 'nested-attributes' in spec: 1402 - child_name = spec['nested-attributes'] 1403 - struct.child_nests.add(child_name) 1404 - child = self.pure_nested_structs.get(child_name) 1405 - if child: 1406 - if not child.recursive: 1407 - struct.child_nests.update(child.child_nests) 1408 - child.request |= struct.request 1409 - child.reply |= struct.reply 1410 - if spec.is_multi_val(): 1411 - child.in_multi_val = True 1412 1289 if attr_set in struct.child_nests: 1413 1290 struct.recursive = True 1291 + 1292 + if 'nested-attributes' in spec: 1293 + child_name = spec['nested-attributes'] 1294 + elif 'sub-message' in spec: 1295 + child_name = spec.sub_message 1296 + else: 1297 + continue 1298 + 1299 + struct.child_nests.add(child_name) 1300 + child = self.pure_nested_structs.get(child_name) 1301 + if child: 1302 + if not child.recursive: 1303 + struct.child_nests.update(child.child_nests) 1304 + child.request |= struct.request 1305 + child.reply |= struct.reply 1306 + if spec.is_multi_val(): 1307 + child.in_multi_val = True 1414 1308 1415 1309 self._sort_pure_types() 1416 1310 ··· 1854 1736 print_prototype(ri, "request") 1855 1737 1856 1738 1739 + def put_typol_submsg(cw, struct): 1740 + cw.block_start(line=f'const struct ynl_policy_attr {struct.render_name}_policy[] =') 1741 + 1742 + i = 0 1743 + for name, arg in struct.member_list(): 1744 + cw.p('[%d] = { .type = YNL_PT_SUBMSG, .name = "%s", .nest = &%s_nest, },' % 1745 + (i, name, arg.nested_render_name)) 1746 + i += 1 1747 + 1748 + cw.block_end(line=';') 1749 + cw.nl() 1750 + 1751 + cw.block_start(line=f'const struct ynl_policy_nest {struct.render_name}_nest =') 1752 + cw.p(f'.max_attr = {i - 1},') 1753 + cw.p(f'.table = {struct.render_name}_policy,') 1754 + cw.block_end(line=';') 1755 + cw.nl() 1756 + 1757 + 1857 1758 def put_typol_fwd(cw, struct): 1858 1759 cw.p(f'extern const struct ynl_policy_nest {struct.render_name}_nest;') 1859 1760 1860 1761 1861 1762 def put_typol(cw, struct): 1763 + if struct.submsg: 1764 + put_typol_submsg(cw, struct) 1765 + return 1766 + 1862 1767 type_max = struct.attr_set.max_name 1863 1768 cw.block_start(line=f'const struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =') 1864 1769 ··· 1967 1826 local_vars = [] 1968 1827 init_lines = [] 1969 1828 1970 - local_vars.append('struct nlattr *nest;') 1971 - init_lines.append("nest = ynl_attr_nest_start(nlh, attr_type);") 1829 + if struct.submsg is None: 1830 + local_vars.append('struct nlattr *nest;') 1831 + init_lines.append("nest = ynl_attr_nest_start(nlh, attr_type);") 1972 1832 1973 1833 has_anest = False 1974 1834 has_count = False ··· 1991 1849 for _, arg in struct.member_list(): 1992 1850 arg.attr_put(ri, "obj") 1993 1851 1994 - ri.cw.p("ynl_attr_nest_end(nlh, nest);") 1852 + if struct.submsg is None: 1853 + ri.cw.p("ynl_attr_nest_end(nlh, nest);") 1995 1854 1996 1855 ri.cw.nl() 1997 1856 ri.cw.p('return 0;') ··· 2029 1886 if 'multi-attr' in aspec: 2030 1887 multi_attrs.add(arg) 2031 1888 needs_parg |= 'nested-attributes' in aspec 1889 + needs_parg |= 'sub-message' in aspec 2032 1890 if array_nests or multi_attrs: 2033 1891 local_vars.append('int i;') 2034 1892 if needs_parg: ··· 2148 2004 ri.cw.nl() 2149 2005 2150 2006 2007 + def parse_rsp_submsg(ri, struct): 2008 + parse_rsp_nested_prototype(ri, struct, suffix='') 2009 + 2010 + var = 'dst' 2011 + 2012 + ri.cw.block_start() 2013 + ri.cw.write_func_lvar(['const struct nlattr *attr = nested;', 2014 + f'{struct.ptr_name}{var} = yarg->data;', 2015 + 'struct ynl_parse_arg parg;']) 2016 + 2017 + ri.cw.p('parg.ys = yarg->ys;') 2018 + ri.cw.nl() 2019 + 2020 + first = True 2021 + for name, arg in struct.member_list(): 2022 + kw = 'if' if first else 'else if' 2023 + first = False 2024 + 2025 + ri.cw.block_start(line=f'{kw} (!strcmp(sel, "{name}"))') 2026 + get_lines, init_lines, _ = arg._attr_get(ri, var) 2027 + for line in init_lines: 2028 + ri.cw.p(line) 2029 + for line in get_lines: 2030 + ri.cw.p(line) 2031 + if arg.presence_type() == 'present': 2032 + ri.cw.p(f"{var}->_present.{arg.c_name} = 1;") 2033 + ri.cw.block_end() 2034 + ri.cw.p('return 0;') 2035 + ri.cw.block_end() 2036 + ri.cw.nl() 2037 + 2038 + 2151 2039 def parse_rsp_nested_prototype(ri, struct, suffix=';'): 2152 2040 func_args = ['struct ynl_parse_arg *yarg', 2153 2041 'const struct nlattr *nested'] 2042 + if struct.submsg: 2043 + func_args.insert(1, 'const char *sel') 2154 2044 for arg in struct.inherited: 2155 2045 func_args.append('__u32 ' + arg) 2156 2046 ··· 2193 2015 2194 2016 2195 2017 def parse_rsp_nested(ri, struct): 2018 + if struct.submsg: 2019 + return parse_rsp_submsg(ri, struct) 2020 + 2196 2021 parse_rsp_nested_prototype(ri, struct, suffix='') 2197 2022 2198 2023 local_vars = ['const struct nlattr *attr;', ··· 3483 3302 has_recursive_nests = True 3484 3303 if has_recursive_nests: 3485 3304 cw.nl() 3486 - for name in parsed.pure_nested_structs: 3487 - struct = Struct(parsed, name) 3305 + for struct in parsed.pure_nested_structs.values(): 3488 3306 put_typol(cw, struct) 3489 3307 for name in parsed.root_sets: 3490 3308 struct = Struct(parsed, name)
+1
tools/net/ynl/samples/.gitignore
··· 4 4 ovs 5 5 page-pool 6 6 rt-addr 7 + rt-link 7 8 rt-route
+184
tools/net/ynl/samples/rt-link.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <string.h> 4 + 5 + #include <ynl.h> 6 + 7 + #include <arpa/inet.h> 8 + #include <net/if.h> 9 + 10 + #include "rt-link-user.h" 11 + 12 + static void rt_link_print(struct rt_link_getlink_rsp *r) 13 + { 14 + unsigned int i; 15 + 16 + printf("%3d: ", r->_hdr.ifi_index); 17 + 18 + if (r->_len.ifname) 19 + printf("%16s: ", r->ifname); 20 + 21 + if (r->_present.mtu) 22 + printf("mtu %5d ", r->mtu); 23 + 24 + if (r->linkinfo._len.kind) 25 + printf("kind %-8s ", r->linkinfo.kind); 26 + else 27 + printf(" %8s ", ""); 28 + 29 + if (r->prop_list._count.alt_ifname) { 30 + printf("altname "); 31 + for (i = 0; i < r->prop_list._count.alt_ifname; i++) 32 + printf("%s ", r->prop_list.alt_ifname[i]->str); 33 + printf(" "); 34 + } 35 + 36 + if (r->linkinfo._present.data && r->linkinfo.data._present.netkit) { 37 + struct rt_link_linkinfo_netkit_attrs *netkit; 38 + const char *name; 39 + 40 + netkit = &r->linkinfo.data.netkit; 41 + printf("primary %d ", netkit->primary); 42 + 43 + name = NULL; 44 + if (netkit->_present.policy) 45 + name = rt_link_netkit_policy_str(netkit->policy); 46 + if (name) 47 + printf("policy %s ", name); 48 + } 49 + 50 + printf("\n"); 51 + } 52 + 53 + static int rt_link_create_netkit(struct ynl_sock *ys) 54 + { 55 + struct rt_link_getlink_ntf *ntf_gl; 56 + struct rt_link_newlink_req *req; 57 + struct ynl_ntf_base_type *ntf; 58 + int ret; 59 + 60 + req = rt_link_newlink_req_alloc(); 61 + if (!req) { 62 + fprintf(stderr, "Can't alloc req\n"); 63 + return -1; 64 + } 65 + 66 + /* rtnetlink doesn't provide info about the created object. 67 + * It expects us to set the ECHO flag and the dig the info out 68 + * of the notifications... 69 + */ 70 + rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO); 71 + 72 + rt_link_newlink_req_set_linkinfo_kind(req, "netkit"); 73 + 74 + /* Test error messages */ 75 + rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10); 76 + ret = rt_link_newlink(ys, req); 77 + if (ret) { 78 + printf("Testing error message for policy being bad:\n\t%s\n", ys->err.msg); 79 + } else { 80 + fprintf(stderr, "Warning: unexpected success creating netkit with bad attrs\n"); 81 + goto created; 82 + } 83 + 84 + rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP); 85 + 86 + ret = rt_link_newlink(ys, req); 87 + created: 88 + rt_link_newlink_req_free(req); 89 + if (ret) { 90 + fprintf(stderr, "YNL: %s\n", ys->err.msg); 91 + return -1; 92 + } 93 + 94 + if (!ynl_has_ntf(ys)) { 95 + fprintf(stderr, 96 + "Warning: interface created but received no notification, won't delete the interface\n"); 97 + return 0; 98 + } 99 + 100 + ntf = ynl_ntf_dequeue(ys); 101 + if (ntf->cmd != RTM_NEWLINK) { 102 + fprintf(stderr, 103 + "Warning: unexpected notification type, won't delete the interface\n"); 104 + return 0; 105 + } 106 + ntf_gl = (void *)ntf; 107 + ret = ntf_gl->obj._hdr.ifi_index; 108 + ynl_ntf_free(ntf); 109 + 110 + return ret; 111 + } 112 + 113 + static void rt_link_del(struct ynl_sock *ys, int ifindex) 114 + { 115 + struct rt_link_dellink_req *req; 116 + 117 + req = rt_link_dellink_req_alloc(); 118 + if (!req) { 119 + fprintf(stderr, "Can't alloc req\n"); 120 + return; 121 + } 122 + 123 + req->_hdr.ifi_index = ifindex; 124 + if (rt_link_dellink(ys, req)) 125 + fprintf(stderr, "YNL: %s\n", ys->err.msg); 126 + else 127 + fprintf(stderr, 128 + "Trying to delete a Netkit interface (ifindex %d)\n", 129 + ifindex); 130 + 131 + rt_link_dellink_req_free(req); 132 + } 133 + 134 + int main(int argc, char **argv) 135 + { 136 + struct rt_link_getlink_req_dump *req; 137 + struct rt_link_getlink_list *rsp; 138 + struct ynl_error yerr; 139 + struct ynl_sock *ys; 140 + int created = 0; 141 + 142 + ys = ynl_sock_create(&ynl_rt_link_family, &yerr); 143 + if (!ys) { 144 + fprintf(stderr, "YNL: %s\n", yerr.msg); 145 + return 1; 146 + } 147 + 148 + if (argc > 1) { 149 + fprintf(stderr, "Trying to create a Netkit interface\n"); 150 + created = rt_link_create_netkit(ys); 151 + if (created < 0) 152 + goto err_destroy; 153 + } 154 + 155 + req = rt_link_getlink_req_dump_alloc(); 156 + if (!req) 157 + goto err_del_ifc; 158 + 159 + rsp = rt_link_getlink_dump(ys, req); 160 + rt_link_getlink_req_dump_free(req); 161 + if (!rsp) 162 + goto err_close; 163 + 164 + if (ynl_dump_empty(rsp)) 165 + fprintf(stderr, "Error: no links reported\n"); 166 + ynl_dump_foreach(rsp, link) 167 + rt_link_print(link); 168 + rt_link_getlink_list_free(rsp); 169 + 170 + if (created) 171 + rt_link_del(ys, created); 172 + 173 + ynl_sock_destroy(ys); 174 + return 0; 175 + 176 + err_close: 177 + fprintf(stderr, "YNL: %s\n", ys->err.msg); 178 + err_del_ifc: 179 + if (created) 180 + rt_link_del(ys, created); 181 + err_destroy: 182 + ynl_sock_destroy(ys); 183 + return 2; 184 + }