xref: /freebsd/tests/atf_python/sys/netlink/attrs.py (revision f0ffe1ce0fba262b458399dcd4c5e8c84e024606)
1fee65b7eSAlexander V. Chernikovimport socket
2fee65b7eSAlexander V. Chernikovimport struct
3fee65b7eSAlexander V. Chernikovfrom enum import Enum
4fee65b7eSAlexander V. Chernikov
5388420e6SAlexander V. Chernikovfrom atf_python.sys.netlink.utils import align4
6388420e6SAlexander V. Chernikovfrom atf_python.sys.netlink.utils import enum_or_int
7fee65b7eSAlexander V. Chernikov
8fee65b7eSAlexander V. Chernikov
9fee65b7eSAlexander V. Chernikovclass NlAttr(object):
103e5d0784SAlexander V. Chernikov    HDR_LEN = 4  # sizeof(struct nlattr)
113e5d0784SAlexander V. Chernikov
12fee65b7eSAlexander V. Chernikov    def __init__(self, nla_type, data):
13fee65b7eSAlexander V. Chernikov        if isinstance(nla_type, Enum):
14fee65b7eSAlexander V. Chernikov            self._nla_type = nla_type.value
15fee65b7eSAlexander V. Chernikov            self._enum = nla_type
16fee65b7eSAlexander V. Chernikov        else:
17fee65b7eSAlexander V. Chernikov            self._nla_type = nla_type
18fee65b7eSAlexander V. Chernikov            self._enum = None
19fee65b7eSAlexander V. Chernikov        self.nla_list = []
20fee65b7eSAlexander V. Chernikov        self._data = data
21fee65b7eSAlexander V. Chernikov
22fee65b7eSAlexander V. Chernikov    @property
23fee65b7eSAlexander V. Chernikov    def nla_type(self):
2404a03660SAlexander V. Chernikov        return self._nla_type & 0x3FFF
25fee65b7eSAlexander V. Chernikov
26fee65b7eSAlexander V. Chernikov    @property
27fee65b7eSAlexander V. Chernikov    def nla_len(self):
28fee65b7eSAlexander V. Chernikov        return len(self._data) + 4
29fee65b7eSAlexander V. Chernikov
30fee65b7eSAlexander V. Chernikov    def add_nla(self, nla):
31fee65b7eSAlexander V. Chernikov        self.nla_list.append(nla)
32fee65b7eSAlexander V. Chernikov
33fee65b7eSAlexander V. Chernikov    def print_attr(self, prepend=""):
34fee65b7eSAlexander V. Chernikov        if self._enum is not None:
35fee65b7eSAlexander V. Chernikov            type_str = self._enum.name
36fee65b7eSAlexander V. Chernikov        else:
37fee65b7eSAlexander V. Chernikov            type_str = "nla#{}".format(self.nla_type)
38fee65b7eSAlexander V. Chernikov        print(
39fee65b7eSAlexander V. Chernikov            "{}len={} type={}({}){}".format(
40fee65b7eSAlexander V. Chernikov                prepend, self.nla_len, type_str, self.nla_type, self._print_attr_value()
41fee65b7eSAlexander V. Chernikov            )
42fee65b7eSAlexander V. Chernikov        )
43fee65b7eSAlexander V. Chernikov
44fee65b7eSAlexander V. Chernikov    @staticmethod
45fee65b7eSAlexander V. Chernikov    def _validate(data):
46fee65b7eSAlexander V. Chernikov        if len(data) < 4:
47fee65b7eSAlexander V. Chernikov            raise ValueError("attribute too short")
48fee65b7eSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
49fee65b7eSAlexander V. Chernikov        if nla_len > len(data):
50fee65b7eSAlexander V. Chernikov            raise ValueError("attribute length too big")
51fee65b7eSAlexander V. Chernikov        if nla_len < 4:
52fee65b7eSAlexander V. Chernikov            raise ValueError("attribute length too short")
53fee65b7eSAlexander V. Chernikov
54fee65b7eSAlexander V. Chernikov    @classmethod
55fee65b7eSAlexander V. Chernikov    def _parse(cls, data):
56fee65b7eSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
57fee65b7eSAlexander V. Chernikov        return cls(nla_type, data[4:])
58fee65b7eSAlexander V. Chernikov
59fee65b7eSAlexander V. Chernikov    @classmethod
60fee65b7eSAlexander V. Chernikov    def from_bytes(cls, data, attr_type_enum=None):
61fee65b7eSAlexander V. Chernikov        cls._validate(data)
62fee65b7eSAlexander V. Chernikov        attr = cls._parse(data)
63fee65b7eSAlexander V. Chernikov        attr._enum = attr_type_enum
64fee65b7eSAlexander V. Chernikov        return attr
65fee65b7eSAlexander V. Chernikov
66fee65b7eSAlexander V. Chernikov    def _to_bytes(self, data: bytes):
67fee65b7eSAlexander V. Chernikov        ret = data
68fee65b7eSAlexander V. Chernikov        if align4(len(ret)) != len(ret):
69fee65b7eSAlexander V. Chernikov            ret = data + bytes(align4(len(ret)) - len(ret))
70fee65b7eSAlexander V. Chernikov        return struct.pack("@HH", len(data) + 4, self._nla_type) + ret
71fee65b7eSAlexander V. Chernikov
72fee65b7eSAlexander V. Chernikov    def __bytes__(self):
73fee65b7eSAlexander V. Chernikov        return self._to_bytes(self._data)
74fee65b7eSAlexander V. Chernikov
75fee65b7eSAlexander V. Chernikov    def _print_attr_value(self):
76fee65b7eSAlexander V. Chernikov        return " " + " ".join(["x{:02X}".format(b) for b in self._data])
77fee65b7eSAlexander V. Chernikov
78fee65b7eSAlexander V. Chernikov
79fee65b7eSAlexander V. Chernikovclass NlAttrNested(NlAttr):
80fee65b7eSAlexander V. Chernikov    def __init__(self, nla_type, val):
81fee65b7eSAlexander V. Chernikov        super().__init__(nla_type, b"")
82fee65b7eSAlexander V. Chernikov        self.nla_list = val
83fee65b7eSAlexander V. Chernikov
84*f0ffe1ceSAlexander V. Chernikov    def get_nla(self, nla_type):
85*f0ffe1ceSAlexander V. Chernikov        nla_type_raw = enum_or_int(nla_type)
86*f0ffe1ceSAlexander V. Chernikov        for nla in self.nla_list:
87*f0ffe1ceSAlexander V. Chernikov            if nla.nla_type == nla_type_raw:
88*f0ffe1ceSAlexander V. Chernikov                return nla
89*f0ffe1ceSAlexander V. Chernikov        return None
90*f0ffe1ceSAlexander V. Chernikov
91fee65b7eSAlexander V. Chernikov    @property
92fee65b7eSAlexander V. Chernikov    def nla_len(self):
93fee65b7eSAlexander V. Chernikov        return align4(len(b"".join([bytes(nla) for nla in self.nla_list]))) + 4
94fee65b7eSAlexander V. Chernikov
95fee65b7eSAlexander V. Chernikov    def print_attr(self, prepend=""):
96fee65b7eSAlexander V. Chernikov        if self._enum is not None:
97fee65b7eSAlexander V. Chernikov            type_str = self._enum.name
98fee65b7eSAlexander V. Chernikov        else:
99fee65b7eSAlexander V. Chernikov            type_str = "nla#{}".format(self.nla_type)
100fee65b7eSAlexander V. Chernikov        print(
101fee65b7eSAlexander V. Chernikov            "{}len={} type={}({}) {{".format(
102fee65b7eSAlexander V. Chernikov                prepend, self.nla_len, type_str, self.nla_type
103fee65b7eSAlexander V. Chernikov            )
104fee65b7eSAlexander V. Chernikov        )
105fee65b7eSAlexander V. Chernikov        for nla in self.nla_list:
106fee65b7eSAlexander V. Chernikov            nla.print_attr(prepend + "  ")
107fee65b7eSAlexander V. Chernikov        print("{}}}".format(prepend))
108fee65b7eSAlexander V. Chernikov
109fee65b7eSAlexander V. Chernikov    def __bytes__(self):
110fee65b7eSAlexander V. Chernikov        return self._to_bytes(b"".join([bytes(nla) for nla in self.nla_list]))
111fee65b7eSAlexander V. Chernikov
112fee65b7eSAlexander V. Chernikov
113fee65b7eSAlexander V. Chernikovclass NlAttrU32(NlAttr):
114fee65b7eSAlexander V. Chernikov    def __init__(self, nla_type, val):
115fee65b7eSAlexander V. Chernikov        self.u32 = enum_or_int(val)
116fee65b7eSAlexander V. Chernikov        super().__init__(nla_type, b"")
117fee65b7eSAlexander V. Chernikov
118fee65b7eSAlexander V. Chernikov    @property
119fee65b7eSAlexander V. Chernikov    def nla_len(self):
120fee65b7eSAlexander V. Chernikov        return 8
121fee65b7eSAlexander V. Chernikov
122fee65b7eSAlexander V. Chernikov    def _print_attr_value(self):
123fee65b7eSAlexander V. Chernikov        return " val={}".format(self.u32)
124fee65b7eSAlexander V. Chernikov
125fee65b7eSAlexander V. Chernikov    @staticmethod
126fee65b7eSAlexander V. Chernikov    def _validate(data):
127fee65b7eSAlexander V. Chernikov        assert len(data) == 8
128fee65b7eSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
129fee65b7eSAlexander V. Chernikov        assert nla_len == 8
130fee65b7eSAlexander V. Chernikov
131fee65b7eSAlexander V. Chernikov    @classmethod
132fee65b7eSAlexander V. Chernikov    def _parse(cls, data):
133fee65b7eSAlexander V. Chernikov        nla_len, nla_type, val = struct.unpack("@HHI", data)
134fee65b7eSAlexander V. Chernikov        return cls(nla_type, val)
135fee65b7eSAlexander V. Chernikov
136fee65b7eSAlexander V. Chernikov    def __bytes__(self):
137fee65b7eSAlexander V. Chernikov        return self._to_bytes(struct.pack("@I", self.u32))
138fee65b7eSAlexander V. Chernikov
139fee65b7eSAlexander V. Chernikov
140*f0ffe1ceSAlexander V. Chernikovclass NlAttrS32(NlAttr):
141*f0ffe1ceSAlexander V. Chernikov    def __init__(self, nla_type, val):
142*f0ffe1ceSAlexander V. Chernikov        self.s32 = enum_or_int(val)
143*f0ffe1ceSAlexander V. Chernikov        super().__init__(nla_type, b"")
144*f0ffe1ceSAlexander V. Chernikov
145*f0ffe1ceSAlexander V. Chernikov    @property
146*f0ffe1ceSAlexander V. Chernikov    def nla_len(self):
147*f0ffe1ceSAlexander V. Chernikov        return 8
148*f0ffe1ceSAlexander V. Chernikov
149*f0ffe1ceSAlexander V. Chernikov    def _print_attr_value(self):
150*f0ffe1ceSAlexander V. Chernikov        return " val={}".format(self.s32)
151*f0ffe1ceSAlexander V. Chernikov
152*f0ffe1ceSAlexander V. Chernikov    @staticmethod
153*f0ffe1ceSAlexander V. Chernikov    def _validate(data):
154*f0ffe1ceSAlexander V. Chernikov        assert len(data) == 8
155*f0ffe1ceSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
156*f0ffe1ceSAlexander V. Chernikov        assert nla_len == 8
157*f0ffe1ceSAlexander V. Chernikov
158*f0ffe1ceSAlexander V. Chernikov    @classmethod
159*f0ffe1ceSAlexander V. Chernikov    def _parse(cls, data):
160*f0ffe1ceSAlexander V. Chernikov        nla_len, nla_type, val = struct.unpack("@HHi", data)
161*f0ffe1ceSAlexander V. Chernikov        return cls(nla_type, val)
162*f0ffe1ceSAlexander V. Chernikov
163*f0ffe1ceSAlexander V. Chernikov    def __bytes__(self):
164*f0ffe1ceSAlexander V. Chernikov        return self._to_bytes(struct.pack("@i", self.s32))
165*f0ffe1ceSAlexander V. Chernikov
166*f0ffe1ceSAlexander V. Chernikov
167fee65b7eSAlexander V. Chernikovclass NlAttrU16(NlAttr):
168fee65b7eSAlexander V. Chernikov    def __init__(self, nla_type, val):
169fee65b7eSAlexander V. Chernikov        self.u16 = enum_or_int(val)
170fee65b7eSAlexander V. Chernikov        super().__init__(nla_type, b"")
171fee65b7eSAlexander V. Chernikov
172fee65b7eSAlexander V. Chernikov    @property
173fee65b7eSAlexander V. Chernikov    def nla_len(self):
174fee65b7eSAlexander V. Chernikov        return 6
175fee65b7eSAlexander V. Chernikov
176fee65b7eSAlexander V. Chernikov    def _print_attr_value(self):
177fee65b7eSAlexander V. Chernikov        return " val={}".format(self.u16)
178fee65b7eSAlexander V. Chernikov
179fee65b7eSAlexander V. Chernikov    @staticmethod
180fee65b7eSAlexander V. Chernikov    def _validate(data):
181fee65b7eSAlexander V. Chernikov        assert len(data) == 6
182fee65b7eSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
183fee65b7eSAlexander V. Chernikov        assert nla_len == 6
184fee65b7eSAlexander V. Chernikov
185fee65b7eSAlexander V. Chernikov    @classmethod
186fee65b7eSAlexander V. Chernikov    def _parse(cls, data):
187fee65b7eSAlexander V. Chernikov        nla_len, nla_type, val = struct.unpack("@HHH", data)
188fee65b7eSAlexander V. Chernikov        return cls(nla_type, val)
189fee65b7eSAlexander V. Chernikov
190fee65b7eSAlexander V. Chernikov    def __bytes__(self):
191fee65b7eSAlexander V. Chernikov        return self._to_bytes(struct.pack("@H", self.u16))
192fee65b7eSAlexander V. Chernikov
193fee65b7eSAlexander V. Chernikov
194fee65b7eSAlexander V. Chernikovclass NlAttrU8(NlAttr):
195fee65b7eSAlexander V. Chernikov    def __init__(self, nla_type, val):
196fee65b7eSAlexander V. Chernikov        self.u8 = enum_or_int(val)
197fee65b7eSAlexander V. Chernikov        super().__init__(nla_type, b"")
198fee65b7eSAlexander V. Chernikov
199fee65b7eSAlexander V. Chernikov    @property
200fee65b7eSAlexander V. Chernikov    def nla_len(self):
201fee65b7eSAlexander V. Chernikov        return 5
202fee65b7eSAlexander V. Chernikov
203fee65b7eSAlexander V. Chernikov    def _print_attr_value(self):
204fee65b7eSAlexander V. Chernikov        return " val={}".format(self.u8)
205fee65b7eSAlexander V. Chernikov
206fee65b7eSAlexander V. Chernikov    @staticmethod
207fee65b7eSAlexander V. Chernikov    def _validate(data):
208fee65b7eSAlexander V. Chernikov        assert len(data) == 5
209fee65b7eSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
210fee65b7eSAlexander V. Chernikov        assert nla_len == 5
211fee65b7eSAlexander V. Chernikov
212fee65b7eSAlexander V. Chernikov    @classmethod
213fee65b7eSAlexander V. Chernikov    def _parse(cls, data):
214fee65b7eSAlexander V. Chernikov        nla_len, nla_type, val = struct.unpack("@HHB", data)
215fee65b7eSAlexander V. Chernikov        return cls(nla_type, val)
216fee65b7eSAlexander V. Chernikov
217fee65b7eSAlexander V. Chernikov    def __bytes__(self):
218fee65b7eSAlexander V. Chernikov        return self._to_bytes(struct.pack("@B", self.u8))
219fee65b7eSAlexander V. Chernikov
220fee65b7eSAlexander V. Chernikov
221fee65b7eSAlexander V. Chernikovclass NlAttrIp(NlAttr):
222fee65b7eSAlexander V. Chernikov    def __init__(self, nla_type, addr: str):
223fee65b7eSAlexander V. Chernikov        super().__init__(nla_type, b"")
224fee65b7eSAlexander V. Chernikov        self.addr = addr
225fee65b7eSAlexander V. Chernikov        if ":" in self.addr:
226fee65b7eSAlexander V. Chernikov            self.family = socket.AF_INET6
227fee65b7eSAlexander V. Chernikov        else:
228fee65b7eSAlexander V. Chernikov            self.family = socket.AF_INET
229fee65b7eSAlexander V. Chernikov
230fee65b7eSAlexander V. Chernikov    @staticmethod
231fee65b7eSAlexander V. Chernikov    def _validate(data):
232fee65b7eSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
233fee65b7eSAlexander V. Chernikov        data_len = nla_len - 4
234fee65b7eSAlexander V. Chernikov        if data_len != 4 and data_len != 16:
235fee65b7eSAlexander V. Chernikov            raise ValueError(
236fee65b7eSAlexander V. Chernikov                "Error validating attr {}: nla_len is not valid".format(  # noqa: E501
237fee65b7eSAlexander V. Chernikov                    nla_type
238fee65b7eSAlexander V. Chernikov                )
239fee65b7eSAlexander V. Chernikov            )
240fee65b7eSAlexander V. Chernikov
241fee65b7eSAlexander V. Chernikov    @property
242fee65b7eSAlexander V. Chernikov    def nla_len(self):
243fee65b7eSAlexander V. Chernikov        if self.family == socket.AF_INET6:
244fee65b7eSAlexander V. Chernikov            return 20
245fee65b7eSAlexander V. Chernikov        else:
246fee65b7eSAlexander V. Chernikov            return 8
247fee65b7eSAlexander V. Chernikov        return align4(len(self._data)) + 4
248fee65b7eSAlexander V. Chernikov
249fee65b7eSAlexander V. Chernikov    @classmethod
250fee65b7eSAlexander V. Chernikov    def _parse(cls, data):
251fee65b7eSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
252fee65b7eSAlexander V. Chernikov        data_len = len(data) - 4
253fee65b7eSAlexander V. Chernikov        if data_len == 4:
254fee65b7eSAlexander V. Chernikov            addr = socket.inet_ntop(socket.AF_INET, data[4:8])
255fee65b7eSAlexander V. Chernikov        else:
256fee65b7eSAlexander V. Chernikov            addr = socket.inet_ntop(socket.AF_INET6, data[4:20])
257fee65b7eSAlexander V. Chernikov        return cls(nla_type, addr)
258fee65b7eSAlexander V. Chernikov
259fee65b7eSAlexander V. Chernikov    def __bytes__(self):
260fee65b7eSAlexander V. Chernikov        return self._to_bytes(socket.inet_pton(self.family, self.addr))
261fee65b7eSAlexander V. Chernikov
262fee65b7eSAlexander V. Chernikov    def _print_attr_value(self):
263fee65b7eSAlexander V. Chernikov        return " addr={}".format(self.addr)
264fee65b7eSAlexander V. Chernikov
265fee65b7eSAlexander V. Chernikov
266*f0ffe1ceSAlexander V. Chernikovclass NlAttrIp4(NlAttrIp):
267*f0ffe1ceSAlexander V. Chernikov    def __init__(self, nla_type, addr: str):
268*f0ffe1ceSAlexander V. Chernikov        super().__init__(nla_type, addr)
269*f0ffe1ceSAlexander V. Chernikov        assert self.family == socket.AF_INET
270*f0ffe1ceSAlexander V. Chernikov
271*f0ffe1ceSAlexander V. Chernikov
272*f0ffe1ceSAlexander V. Chernikovclass NlAttrIp6(NlAttrIp):
273*f0ffe1ceSAlexander V. Chernikov    def __init__(self, nla_type, addr: str):
274*f0ffe1ceSAlexander V. Chernikov        super().__init__(nla_type, addr)
275*f0ffe1ceSAlexander V. Chernikov        assert self.family == socket.AF_INET6
276*f0ffe1ceSAlexander V. Chernikov
277*f0ffe1ceSAlexander V. Chernikov
278fee65b7eSAlexander V. Chernikovclass NlAttrStr(NlAttr):
279fee65b7eSAlexander V. Chernikov    def __init__(self, nla_type, text):
280fee65b7eSAlexander V. Chernikov        super().__init__(nla_type, b"")
281fee65b7eSAlexander V. Chernikov        self.text = text
282fee65b7eSAlexander V. Chernikov
283fee65b7eSAlexander V. Chernikov    @staticmethod
284fee65b7eSAlexander V. Chernikov    def _validate(data):
285fee65b7eSAlexander V. Chernikov        NlAttr._validate(data)
286fee65b7eSAlexander V. Chernikov        try:
287fee65b7eSAlexander V. Chernikov            data[4:].decode("utf-8")
288fee65b7eSAlexander V. Chernikov        except Exception as e:
289fee65b7eSAlexander V. Chernikov            raise ValueError("wrong utf-8 string: {}".format(e))
290fee65b7eSAlexander V. Chernikov
291fee65b7eSAlexander V. Chernikov    @property
292fee65b7eSAlexander V. Chernikov    def nla_len(self):
293fee65b7eSAlexander V. Chernikov        return len(self.text) + 5
294fee65b7eSAlexander V. Chernikov
295fee65b7eSAlexander V. Chernikov    @classmethod
296fee65b7eSAlexander V. Chernikov    def _parse(cls, data):
297fee65b7eSAlexander V. Chernikov        text = data[4:-1].decode("utf-8")
298fee65b7eSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
299fee65b7eSAlexander V. Chernikov        return cls(nla_type, text)
300fee65b7eSAlexander V. Chernikov
301fee65b7eSAlexander V. Chernikov    def __bytes__(self):
302fee65b7eSAlexander V. Chernikov        return self._to_bytes(bytes(self.text, encoding="utf-8") + bytes(1))
303fee65b7eSAlexander V. Chernikov
304fee65b7eSAlexander V. Chernikov    def _print_attr_value(self):
305fee65b7eSAlexander V. Chernikov        return ' val="{}"'.format(self.text)
306fee65b7eSAlexander V. Chernikov
307fee65b7eSAlexander V. Chernikov
308fee65b7eSAlexander V. Chernikovclass NlAttrStrn(NlAttr):
309fee65b7eSAlexander V. Chernikov    def __init__(self, nla_type, text):
310fee65b7eSAlexander V. Chernikov        super().__init__(nla_type, b"")
311fee65b7eSAlexander V. Chernikov        self.text = text
312fee65b7eSAlexander V. Chernikov
313fee65b7eSAlexander V. Chernikov    @staticmethod
314fee65b7eSAlexander V. Chernikov    def _validate(data):
315fee65b7eSAlexander V. Chernikov        NlAttr._validate(data)
316fee65b7eSAlexander V. Chernikov        try:
317fee65b7eSAlexander V. Chernikov            data[4:].decode("utf-8")
318fee65b7eSAlexander V. Chernikov        except Exception as e:
319fee65b7eSAlexander V. Chernikov            raise ValueError("wrong utf-8 string: {}".format(e))
320fee65b7eSAlexander V. Chernikov
321fee65b7eSAlexander V. Chernikov    @property
322fee65b7eSAlexander V. Chernikov    def nla_len(self):
323fee65b7eSAlexander V. Chernikov        return len(self.text) + 4
324fee65b7eSAlexander V. Chernikov
325fee65b7eSAlexander V. Chernikov    @classmethod
326fee65b7eSAlexander V. Chernikov    def _parse(cls, data):
327fee65b7eSAlexander V. Chernikov        text = data[4:].decode("utf-8")
328fee65b7eSAlexander V. Chernikov        nla_len, nla_type = struct.unpack("@HH", data[:4])
329fee65b7eSAlexander V. Chernikov        return cls(nla_type, text)
330fee65b7eSAlexander V. Chernikov
331fee65b7eSAlexander V. Chernikov    def __bytes__(self):
332fee65b7eSAlexander V. Chernikov        return self._to_bytes(bytes(self.text, encoding="utf-8"))
333fee65b7eSAlexander V. Chernikov
334fee65b7eSAlexander V. Chernikov    def _print_attr_value(self):
335fee65b7eSAlexander V. Chernikov        return ' val="{}"'.format(self.text)
336