Merge tag 'powerpc-6.6-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[platform/kernel/linux-starfive.git] / tools / testing / selftests / net / openvswitch / ovs-dpctl.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: GPL-2.0
3
4 # Controls the openvswitch module.  Part of the kselftest suite, but
5 # can be used for some diagnostic purpose as well.
6
7 import argparse
8 import errno
9 import ipaddress
10 import logging
11 import multiprocessing
12 import re
13 import struct
14 import sys
15 import time
16 import types
17 import uuid
18
19 try:
20     from pyroute2 import NDB
21
22     from pyroute2.netlink import NLA_F_NESTED
23     from pyroute2.netlink import NLM_F_ACK
24     from pyroute2.netlink import NLM_F_DUMP
25     from pyroute2.netlink import NLM_F_REQUEST
26     from pyroute2.netlink import genlmsg
27     from pyroute2.netlink import nla
28     from pyroute2.netlink import nlmsg_atoms
29     from pyroute2.netlink.exceptions import NetlinkError
30     from pyroute2.netlink.generic import GenericNetlinkSocket
31     import pyroute2
32
33 except ModuleNotFoundError:
34     print("Need to install the python pyroute2 package >= 0.6.")
35     sys.exit(0)
36
37
38 OVS_DATAPATH_FAMILY = "ovs_datapath"
39 OVS_VPORT_FAMILY = "ovs_vport"
40 OVS_FLOW_FAMILY = "ovs_flow"
41 OVS_PACKET_FAMILY = "ovs_packet"
42 OVS_METER_FAMILY = "ovs_meter"
43 OVS_CT_LIMIT_FAMILY = "ovs_ct_limit"
44
45 OVS_DATAPATH_VERSION = 2
46 OVS_DP_CMD_NEW = 1
47 OVS_DP_CMD_DEL = 2
48 OVS_DP_CMD_GET = 3
49 OVS_DP_CMD_SET = 4
50
51 OVS_VPORT_CMD_NEW = 1
52 OVS_VPORT_CMD_DEL = 2
53 OVS_VPORT_CMD_GET = 3
54 OVS_VPORT_CMD_SET = 4
55
56 OVS_FLOW_CMD_NEW = 1
57 OVS_FLOW_CMD_DEL = 2
58 OVS_FLOW_CMD_GET = 3
59 OVS_FLOW_CMD_SET = 4
60
61
62 def macstr(mac):
63     outstr = ":".join(["%02X" % i for i in mac])
64     return outstr
65
66
67 def strcspn(str1, str2):
68     tot = 0
69     for char in str1:
70         if str2.find(char) != -1:
71             return tot
72         tot += 1
73     return tot
74
75
76 def strspn(str1, str2):
77     tot = 0
78     for char in str1:
79         if str2.find(char) == -1:
80             return tot
81         tot += 1
82     return tot
83
84
85 def intparse(statestr, defmask="0xffffffff"):
86     totalparse = strspn(statestr, "0123456789abcdefABCDEFx/")
87     # scan until "/"
88     count = strspn(statestr, "x0123456789abcdefABCDEF")
89
90     firstnum = statestr[:count]
91     if firstnum[-1] == "/":
92         firstnum = firstnum[:-1]
93     k = int(firstnum, 0)
94
95     m = None
96     if defmask is not None:
97         secondnum = defmask
98         if statestr[count] == "/":
99             secondnum = statestr[count + 1 :]  # this is wrong...
100         m = int(secondnum, 0)
101
102     return statestr[totalparse + 1 :], k, m
103
104
105 def parse_flags(flag_str, flag_vals):
106     bitResult = 0
107     maskResult = 0
108
109     if len(flag_str) == 0:
110         return flag_str, bitResult, maskResult
111
112     if flag_str[0].isdigit():
113         idx = 0
114         while flag_str[idx].isdigit() or flag_str[idx] == "x":
115             idx += 1
116         digits = flag_str[:idx]
117         flag_str = flag_str[idx:]
118
119         bitResult = int(digits, 0)
120         maskResult = int(digits, 0)
121
122     while len(flag_str) > 0 and (flag_str[0] == "+" or flag_str[0] == "-"):
123         if flag_str[0] == "+":
124             setFlag = True
125         elif flag_str[0] == "-":
126             setFlag = False
127
128         flag_str = flag_str[1:]
129
130         flag_len = 0
131         while (
132             flag_str[flag_len] != "+"
133             and flag_str[flag_len] != "-"
134             and flag_str[flag_len] != ","
135             and flag_str[flag_len] != ")"
136         ):
137             flag_len += 1
138
139         flag = flag_str[0:flag_len]
140
141         if flag in flag_vals:
142             if maskResult & flag_vals[flag]:
143                 raise KeyError(
144                     "Flag %s set once, cannot be set in multiples" % flag
145                 )
146
147             if setFlag:
148                 bitResult |= flag_vals[flag]
149
150             maskResult |= flag_vals[flag]
151         else:
152             raise KeyError("Missing flag value: %s" % flag)
153
154         flag_str = flag_str[flag_len:]
155
156     return flag_str, bitResult, maskResult
157
158
159 def parse_ct_state(statestr):
160     ct_flags = {
161         "new": 1 << 0,
162         "est": 1 << 1,
163         "rel": 1 << 2,
164         "rpl": 1 << 3,
165         "inv": 1 << 4,
166         "trk": 1 << 5,
167         "snat": 1 << 6,
168         "dnat": 1 << 7,
169     }
170
171     return parse_flags(statestr, ct_flags)
172
173
174 def convert_mac(data):
175     def to_bytes(mac):
176         mac_split = mac.split(":")
177         ret = bytearray([int(i, 16) for i in mac_split])
178         return bytes(ret)
179
180     mac_str, _, mask_str = data.partition('/')
181
182     if not mac_str:
183         mac_str = mask_str = "00:00:00:00:00:00"
184     elif not mask_str:
185         mask_str = "FF:FF:FF:FF:FF:FF"
186
187     return to_bytes(mac_str), to_bytes(mask_str)
188
189 def convert_ipv4(data):
190     ip, _, mask = data.partition('/')
191
192     if not ip:
193         ip = mask = 0
194     elif not mask:
195         mask = 0xFFFFFFFF
196     elif mask.isdigit():
197         mask = (0xFFFFFFFF << (32 - int(mask))) & 0xFFFFFFFF
198
199     return int(ipaddress.IPv4Address(ip)), int(ipaddress.IPv4Address(mask))
200
201 def convert_int(size):
202     def convert_int_sized(data):
203         value, _, mask = data.partition('/')
204
205         if not value:
206             return 0, 0
207         elif not mask:
208             return int(value, 0), pow(2, size) - 1
209         else:
210             return int(value, 0), int(mask, 0)
211
212     return convert_int_sized
213
214 def parse_starts_block(block_str, scanstr, returnskipped, scanregex=False):
215     if scanregex:
216         m = re.search(scanstr, block_str)
217         if m is None:
218             if returnskipped:
219                 return block_str
220             return False
221         if returnskipped:
222             block_str = block_str[len(m.group(0)) :]
223             return block_str
224         return True
225
226     if block_str.startswith(scanstr):
227         if returnskipped:
228             block_str = block_str[len(scanstr) :]
229         else:
230             return True
231
232     if returnskipped:
233         return block_str
234
235     return False
236
237
238 def parse_extract_field(
239     block_str, fieldstr, scanfmt, convert, masked=False, defval=None
240 ):
241     if fieldstr and not block_str.startswith(fieldstr):
242         return block_str, defval
243
244     if fieldstr:
245         str_skiplen = len(fieldstr)
246         str_skipped = block_str[str_skiplen:]
247         if str_skiplen == 0:
248             return str_skipped, defval
249     else:
250         str_skiplen = 0
251         str_skipped = block_str
252
253     m = re.search(scanfmt, str_skipped)
254     if m is None:
255         raise ValueError("Bad fmt string")
256
257     data = m.group(0)
258     if convert:
259         data = convert(m.group(0))
260
261     str_skipped = str_skipped[len(m.group(0)) :]
262     if masked:
263         if str_skipped[0] == "/":
264             raise ValueError("Masking support TBD...")
265
266     str_skipped = str_skipped[strspn(str_skipped, ", ") :]
267     return str_skipped, data
268
269
270 class ovs_dp_msg(genlmsg):
271     # include the OVS version
272     # We need a custom header rather than just being able to rely on
273     # genlmsg because fields ends up not expressing everything correctly
274     # if we use the canonical example of setting fields = (('customfield',),)
275     fields = genlmsg.fields + (("dpifindex", "I"),)
276
277
278 class ovsactions(nla):
279     nla_flags = NLA_F_NESTED
280
281     nla_map = (
282         ("OVS_ACTION_ATTR_UNSPEC", "none"),
283         ("OVS_ACTION_ATTR_OUTPUT", "uint32"),
284         ("OVS_ACTION_ATTR_USERSPACE", "userspace"),
285         ("OVS_ACTION_ATTR_SET", "none"),
286         ("OVS_ACTION_ATTR_PUSH_VLAN", "none"),
287         ("OVS_ACTION_ATTR_POP_VLAN", "flag"),
288         ("OVS_ACTION_ATTR_SAMPLE", "none"),
289         ("OVS_ACTION_ATTR_RECIRC", "uint32"),
290         ("OVS_ACTION_ATTR_HASH", "none"),
291         ("OVS_ACTION_ATTR_PUSH_MPLS", "none"),
292         ("OVS_ACTION_ATTR_POP_MPLS", "flag"),
293         ("OVS_ACTION_ATTR_SET_MASKED", "none"),
294         ("OVS_ACTION_ATTR_CT", "ctact"),
295         ("OVS_ACTION_ATTR_TRUNC", "uint32"),
296         ("OVS_ACTION_ATTR_PUSH_ETH", "none"),
297         ("OVS_ACTION_ATTR_POP_ETH", "flag"),
298         ("OVS_ACTION_ATTR_CT_CLEAR", "flag"),
299         ("OVS_ACTION_ATTR_PUSH_NSH", "none"),
300         ("OVS_ACTION_ATTR_POP_NSH", "flag"),
301         ("OVS_ACTION_ATTR_METER", "none"),
302         ("OVS_ACTION_ATTR_CLONE", "none"),
303         ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"),
304         ("OVS_ACTION_ATTR_ADD_MPLS", "none"),
305         ("OVS_ACTION_ATTR_DEC_TTL", "none"),
306         ("OVS_ACTION_ATTR_DROP", "uint32"),
307     )
308
309     class ctact(nla):
310         nla_flags = NLA_F_NESTED
311
312         nla_map = (
313             ("OVS_CT_ATTR_NONE", "none"),
314             ("OVS_CT_ATTR_COMMIT", "flag"),
315             ("OVS_CT_ATTR_ZONE", "uint16"),
316             ("OVS_CT_ATTR_MARK", "none"),
317             ("OVS_CT_ATTR_LABELS", "none"),
318             ("OVS_CT_ATTR_HELPER", "asciiz"),
319             ("OVS_CT_ATTR_NAT", "natattr"),
320             ("OVS_CT_ATTR_FORCE_COMMIT", "flag"),
321             ("OVS_CT_ATTR_EVENTMASK", "uint32"),
322             ("OVS_CT_ATTR_TIMEOUT", "asciiz"),
323         )
324
325         class natattr(nla):
326             nla_flags = NLA_F_NESTED
327
328             nla_map = (
329                 ("OVS_NAT_ATTR_NONE", "none"),
330                 ("OVS_NAT_ATTR_SRC", "flag"),
331                 ("OVS_NAT_ATTR_DST", "flag"),
332                 ("OVS_NAT_ATTR_IP_MIN", "ipaddr"),
333                 ("OVS_NAT_ATTR_IP_MAX", "ipaddr"),
334                 ("OVS_NAT_ATTR_PROTO_MIN", "uint16"),
335                 ("OVS_NAT_ATTR_PROTO_MAX", "uint16"),
336                 ("OVS_NAT_ATTR_PERSISTENT", "flag"),
337                 ("OVS_NAT_ATTR_PROTO_HASH", "flag"),
338                 ("OVS_NAT_ATTR_PROTO_RANDOM", "flag"),
339             )
340
341             def dpstr(self, more=False):
342                 print_str = "nat("
343
344                 if self.get_attr("OVS_NAT_ATTR_SRC"):
345                     print_str += "src"
346                 elif self.get_attr("OVS_NAT_ATTR_DST"):
347                     print_str += "dst"
348                 else:
349                     print_str += "XXX-unknown-nat"
350
351                 if self.get_attr("OVS_NAT_ATTR_IP_MIN") or self.get_attr(
352                     "OVS_NAT_ATTR_IP_MAX"
353                 ):
354                     if self.get_attr("OVS_NAT_ATTR_IP_MIN"):
355                         print_str += "=%s," % str(
356                             self.get_attr("OVS_NAT_ATTR_IP_MIN")
357                         )
358
359                     if self.get_attr("OVS_NAT_ATTR_IP_MAX"):
360                         print_str += "-%s," % str(
361                             self.get_attr("OVS_NAT_ATTR_IP_MAX")
362                         )
363                 else:
364                     print_str += ","
365
366                 if self.get_attr("OVS_NAT_ATTR_PROTO_MIN"):
367                     print_str += "proto_min=%d," % self.get_attr(
368                         "OVS_NAT_ATTR_PROTO_MIN"
369                     )
370
371                 if self.get_attr("OVS_NAT_ATTR_PROTO_MAX"):
372                     print_str += "proto_max=%d," % self.get_attr(
373                         "OVS_NAT_ATTR_PROTO_MAX"
374                     )
375
376                 if self.get_attr("OVS_NAT_ATTR_PERSISTENT"):
377                     print_str += "persistent,"
378                 if self.get_attr("OVS_NAT_ATTR_HASH"):
379                     print_str += "hash,"
380                 if self.get_attr("OVS_NAT_ATTR_RANDOM"):
381                     print_str += "random"
382                 print_str += ")"
383                 return print_str
384
385         def dpstr(self, more=False):
386             print_str = "ct("
387
388             if self.get_attr("OVS_CT_ATTR_COMMIT") is not None:
389                 print_str += "commit,"
390             if self.get_attr("OVS_CT_ATTR_ZONE") is not None:
391                 print_str += "zone=%d," % self.get_attr("OVS_CT_ATTR_ZONE")
392             if self.get_attr("OVS_CT_ATTR_HELPER") is not None:
393                 print_str += "helper=%s," % self.get_attr("OVS_CT_ATTR_HELPER")
394             if self.get_attr("OVS_CT_ATTR_NAT") is not None:
395                 print_str += self.get_attr("OVS_CT_ATTR_NAT").dpstr(more)
396                 print_str += ","
397             if self.get_attr("OVS_CT_ATTR_FORCE_COMMIT") is not None:
398                 print_str += "force,"
399             if self.get_attr("OVS_CT_ATTR_EVENTMASK") is not None:
400                 print_str += "emask=0x%X," % self.get_attr(
401                     "OVS_CT_ATTR_EVENTMASK"
402                 )
403             if self.get_attr("OVS_CT_ATTR_TIMEOUT") is not None:
404                 print_str += "timeout=%s" % self.get_attr(
405                     "OVS_CT_ATTR_TIMEOUT"
406                 )
407             print_str += ")"
408             return print_str
409
410     class userspace(nla):
411         nla_flags = NLA_F_NESTED
412
413         nla_map = (
414             ("OVS_USERSPACE_ATTR_UNUSED", "none"),
415             ("OVS_USERSPACE_ATTR_PID", "uint32"),
416             ("OVS_USERSPACE_ATTR_USERDATA", "array(uint8)"),
417             ("OVS_USERSPACE_ATTR_EGRESS_TUN_PORT", "uint32"),
418         )
419
420         def dpstr(self, more=False):
421             print_str = "userspace("
422             if self.get_attr("OVS_USERSPACE_ATTR_PID") is not None:
423                 print_str += "pid=%d," % self.get_attr(
424                     "OVS_USERSPACE_ATTR_PID"
425                 )
426             if self.get_attr("OVS_USERSPACE_ATTR_USERDATA") is not None:
427                 print_str += "userdata="
428                 for f in self.get_attr("OVS_USERSPACE_ATTR_USERDATA"):
429                     print_str += "%x." % f
430             if self.get_attr("OVS_USERSPACE_ATTR_TUN_PORT") is not None:
431                 print_str += "egress_tun_port=%d" % self.get_attr(
432                     "OVS_USERSPACE_ATTR_TUN_PORT"
433                 )
434             print_str += ")"
435             return print_str
436
437     def dpstr(self, more=False):
438         print_str = ""
439
440         for field in self.nla_map:
441             if field[1] == "none" or self.get_attr(field[0]) is None:
442                 continue
443             if print_str != "":
444                 print_str += ","
445
446             if field[1] == "uint32":
447                 if field[0] == "OVS_ACTION_ATTR_OUTPUT":
448                     print_str += "%d" % int(self.get_attr(field[0]))
449                 elif field[0] == "OVS_ACTION_ATTR_RECIRC":
450                     print_str += "recirc(0x%x)" % int(self.get_attr(field[0]))
451                 elif field[0] == "OVS_ACTION_ATTR_TRUNC":
452                     print_str += "trunc(%d)" % int(self.get_attr(field[0]))
453                 elif field[0] == "OVS_ACTION_ATTR_DROP":
454                     print_str += "drop(%d)" % int(self.get_attr(field[0]))
455             elif field[1] == "flag":
456                 if field[0] == "OVS_ACTION_ATTR_CT_CLEAR":
457                     print_str += "ct_clear"
458                 elif field[0] == "OVS_ACTION_ATTR_POP_VLAN":
459                     print_str += "pop_vlan"
460                 elif field[0] == "OVS_ACTION_ATTR_POP_ETH":
461                     print_str += "pop_eth"
462                 elif field[0] == "OVS_ACTION_ATTR_POP_NSH":
463                     print_str += "pop_nsh"
464                 elif field[0] == "OVS_ACTION_ATTR_POP_MPLS":
465                     print_str += "pop_mpls"
466             else:
467                 datum = self.get_attr(field[0])
468                 print_str += datum.dpstr(more)
469
470         return print_str
471
472     def parse(self, actstr):
473         while len(actstr) != 0:
474             parsed = False
475             if actstr.startswith("drop"):
476                 # If no reason is provided, the implicit drop is used (i.e no
477                 # action). If some reason is given, an explicit action is used.
478                 actstr, reason = parse_extract_field(
479                     actstr,
480                     "drop(",
481                     "([0-9]+)",
482                     lambda x: int(x, 0),
483                     False,
484                     None,
485                 )
486                 if reason is not None:
487                     self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason])
488                     parsed = True
489                 else:
490                     return
491
492             elif parse_starts_block(actstr, "^(\d+)", False, True):
493                 actstr, output = parse_extract_field(
494                     actstr, None, "(\d+)", lambda x: int(x), False, "0"
495                 )
496                 self["attrs"].append(["OVS_ACTION_ATTR_OUTPUT", output])
497                 parsed = True
498             elif parse_starts_block(actstr, "recirc(", False):
499                 actstr, recircid = parse_extract_field(
500                     actstr,
501                     "recirc(",
502                     "([0-9a-fA-Fx]+)",
503                     lambda x: int(x, 0),
504                     False,
505                     0,
506                 )
507                 self["attrs"].append(["OVS_ACTION_ATTR_RECIRC", recircid])
508                 parsed = True
509
510             parse_flat_map = (
511                 ("ct_clear", "OVS_ACTION_ATTR_CT_CLEAR"),
512                 ("pop_vlan", "OVS_ACTION_ATTR_POP_VLAN"),
513                 ("pop_eth", "OVS_ACTION_ATTR_POP_ETH"),
514                 ("pop_nsh", "OVS_ACTION_ATTR_POP_NSH"),
515             )
516
517             for flat_act in parse_flat_map:
518                 if parse_starts_block(actstr, flat_act[0], False):
519                     actstr += len(flat_act[0])
520                     self["attrs"].append([flat_act[1]])
521                     actstr = actstr[strspn(actstr, ", ") :]
522                     parsed = True
523
524             if parse_starts_block(actstr, "ct(", False):
525                 actstr = actstr[len("ct(") :]
526                 ctact = ovsactions.ctact()
527
528                 for scan in (
529                     ("commit", "OVS_CT_ATTR_COMMIT", None),
530                     ("force_commit", "OVS_CT_ATTR_FORCE_COMMIT", None),
531                     ("zone", "OVS_CT_ATTR_ZONE", int),
532                     ("mark", "OVS_CT_ATTR_MARK", int),
533                     ("helper", "OVS_CT_ATTR_HELPER", lambda x, y: str(x)),
534                     ("timeout", "OVS_CT_ATTR_TIMEOUT", lambda x, y: str(x)),
535                 ):
536                     if actstr.startswith(scan[0]):
537                         actstr = actstr[len(scan[0]) :]
538                         if scan[2] is not None:
539                             if actstr[0] != "=":
540                                 raise ValueError("Invalid ct attr")
541                             actstr = actstr[1:]
542                             pos = strcspn(actstr, ",)")
543                             datum = scan[2](actstr[:pos], 0)
544                             ctact["attrs"].append([scan[1], datum])
545                             actstr = actstr[pos:]
546                         else:
547                             ctact["attrs"].append([scan[1], None])
548                         actstr = actstr[strspn(actstr, ", ") :]
549                     # it seems strange to put this here, but nat() is a complex
550                     # sub-action and this lets it sit anywhere in the ct() action
551                     if actstr.startswith("nat"):
552                         actstr = actstr[3:]
553                         natact = ovsactions.ctact.natattr()
554
555                         if actstr.startswith("("):
556                             t = None
557                             actstr = actstr[1:]
558                             if actstr.startswith("src"):
559                                 t = "OVS_NAT_ATTR_SRC"
560                                 actstr = actstr[3:]
561                             elif actstr.startswith("dst"):
562                                 t = "OVS_NAT_ATTR_DST"
563                                 actstr = actstr[3:]
564
565                             actstr, ip_block_min = parse_extract_field(
566                                 actstr, "=", "([0-9a-fA-F\.]+)", str, False
567                             )
568                             actstr, ip_block_max = parse_extract_field(
569                                 actstr, "-", "([0-9a-fA-F\.]+)", str, False
570                             )
571
572                             actstr, proto_min = parse_extract_field(
573                                 actstr, ":", "(\d+)", int, False
574                             )
575                             actstr, proto_max = parse_extract_field(
576                                 actstr, "-", "(\d+)", int, False
577                             )
578
579                             if t is not None:
580                                 natact["attrs"].append([t, None])
581
582                                 if ip_block_min is not None:
583                                     natact["attrs"].append(
584                                         ["OVS_NAT_ATTR_IP_MIN", ip_block_min]
585                                     )
586                                 if ip_block_max is not None:
587                                     natact["attrs"].append(
588                                         ["OVS_NAT_ATTR_IP_MAX", ip_block_max]
589                                     )
590                                 if proto_min is not None:
591                                     natact["attrs"].append(
592                                         ["OVS_NAT_ATTR_PROTO_MIN", proto_min]
593                                     )
594                                 if proto_max is not None:
595                                     natact["attrs"].append(
596                                         ["OVS_NAT_ATTR_PROTO_MAX", proto_max]
597                                     )
598
599                             for natscan in (
600                                 ("persistent", "OVS_NAT_ATTR_PERSISTENT"),
601                                 ("hash", "OVS_NAT_ATTR_PROTO_HASH"),
602                                 ("random", "OVS_NAT_ATTR_PROTO_RANDOM"),
603                             ):
604                                 if actstr.startswith(natscan[0]):
605                                     actstr = actstr[len(natscan[0]) :]
606                                     natact["attrs"].append([natscan[1], None])
607                                     actstr = actstr[strspn(actstr, ", ") :]
608
609                         ctact["attrs"].append(["OVS_CT_ATTR_NAT", natact])
610                         actstr = actstr[strspn(actstr, ",) ") :]
611
612                 self["attrs"].append(["OVS_ACTION_ATTR_CT", ctact])
613                 parsed = True
614
615             actstr = actstr[strspn(actstr, "), ") :]
616             if not parsed:
617                 raise ValueError("Action str: '%s' not supported" % actstr)
618
619
620 class ovskey(nla):
621     nla_flags = NLA_F_NESTED
622     nla_map = (
623         ("OVS_KEY_ATTR_UNSPEC", "none"),
624         ("OVS_KEY_ATTR_ENCAP", "none"),
625         ("OVS_KEY_ATTR_PRIORITY", "uint32"),
626         ("OVS_KEY_ATTR_IN_PORT", "uint32"),
627         ("OVS_KEY_ATTR_ETHERNET", "ethaddr"),
628         ("OVS_KEY_ATTR_VLAN", "uint16"),
629         ("OVS_KEY_ATTR_ETHERTYPE", "be16"),
630         ("OVS_KEY_ATTR_IPV4", "ovs_key_ipv4"),
631         ("OVS_KEY_ATTR_IPV6", "ovs_key_ipv6"),
632         ("OVS_KEY_ATTR_TCP", "ovs_key_tcp"),
633         ("OVS_KEY_ATTR_UDP", "ovs_key_udp"),
634         ("OVS_KEY_ATTR_ICMP", "ovs_key_icmp"),
635         ("OVS_KEY_ATTR_ICMPV6", "ovs_key_icmpv6"),
636         ("OVS_KEY_ATTR_ARP", "ovs_key_arp"),
637         ("OVS_KEY_ATTR_ND", "ovs_key_nd"),
638         ("OVS_KEY_ATTR_SKB_MARK", "uint32"),
639         ("OVS_KEY_ATTR_TUNNEL", "none"),
640         ("OVS_KEY_ATTR_SCTP", "ovs_key_sctp"),
641         ("OVS_KEY_ATTR_TCP_FLAGS", "be16"),
642         ("OVS_KEY_ATTR_DP_HASH", "uint32"),
643         ("OVS_KEY_ATTR_RECIRC_ID", "uint32"),
644         ("OVS_KEY_ATTR_MPLS", "array(ovs_key_mpls)"),
645         ("OVS_KEY_ATTR_CT_STATE", "uint32"),
646         ("OVS_KEY_ATTR_CT_ZONE", "uint16"),
647         ("OVS_KEY_ATTR_CT_MARK", "uint32"),
648         ("OVS_KEY_ATTR_CT_LABELS", "none"),
649         ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4", "ovs_key_ct_tuple_ipv4"),
650         ("OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6", "ovs_key_ct_tuple_ipv6"),
651         ("OVS_KEY_ATTR_NSH", "none"),
652         ("OVS_KEY_ATTR_PACKET_TYPE", "none"),
653         ("OVS_KEY_ATTR_ND_EXTENSIONS", "none"),
654         ("OVS_KEY_ATTR_TUNNEL_INFO", "none"),
655         ("OVS_KEY_ATTR_IPV6_EXTENSIONS", "none"),
656     )
657
658     class ovs_key_proto(nla):
659         fields = (
660             ("src", "!H"),
661             ("dst", "!H"),
662         )
663
664         fields_map = (
665             ("src", "src", "%d", lambda x: int(x) if x else 0,
666                 convert_int(16)),
667             ("dst", "dst", "%d", lambda x: int(x) if x else 0,
668                 convert_int(16)),
669         )
670
671         def __init__(
672             self,
673             protostr,
674             data=None,
675             offset=None,
676             parent=None,
677             length=None,
678             init=None,
679         ):
680             self.proto_str = protostr
681             nla.__init__(
682                 self,
683                 data=data,
684                 offset=offset,
685                 parent=parent,
686                 length=length,
687                 init=init,
688             )
689
690         def parse(self, flowstr, typeInst):
691             if not flowstr.startswith(self.proto_str):
692                 return None, None
693
694             k = typeInst()
695             m = typeInst()
696
697             flowstr = flowstr[len(self.proto_str) :]
698             if flowstr.startswith("("):
699                 flowstr = flowstr[1:]
700
701             keybits = b""
702             maskbits = b""
703             for f in self.fields_map:
704                 if flowstr.startswith(f[1]):
705                     # the following assumes that the field looks
706                     # something like 'field.' where '.' is a
707                     # character that we don't exactly care about.
708                     flowstr = flowstr[len(f[1]) + 1 :]
709                     splitchar = 0
710                     for c in flowstr:
711                         if c == "," or c == ")":
712                             break
713                         splitchar += 1
714                     data = flowstr[:splitchar]
715                     flowstr = flowstr[splitchar:]
716                 else:
717                     data = ""
718
719                 if len(f) > 4:
720                     k[f[0]], m[f[0]] = f[4](data)
721                 else:
722                     k[f[0]] = f[3](data)
723                     m[f[0]] = f[3](data)
724
725                 flowstr = flowstr[strspn(flowstr, ", ") :]
726                 if len(flowstr) == 0:
727                     return flowstr, k, m
728
729             flowstr = flowstr[strspn(flowstr, "), ") :]
730
731             return flowstr, k, m
732
733         def dpstr(self, masked=None, more=False):
734             outstr = self.proto_str + "("
735             first = False
736             for f in self.fields_map:
737                 if first:
738                     outstr += ","
739                 if masked is None:
740                     outstr += "%s=" % f[0]
741                     if isinstance(f[2], str):
742                         outstr += f[2] % self[f[1]]
743                     else:
744                         outstr += f[2](self[f[1]])
745                     first = True
746                 elif more or f[3](masked[f[1]]) != 0:
747                     outstr += "%s=" % f[0]
748                     if isinstance(f[2], str):
749                         outstr += f[2] % self[f[1]]
750                     else:
751                         outstr += f[2](self[f[1]])
752                     outstr += "/"
753                     if isinstance(f[2], str):
754                         outstr += f[2] % masked[f[1]]
755                     else:
756                         outstr += f[2](masked[f[1]])
757                     first = True
758             outstr += ")"
759             return outstr
760
761     class ethaddr(ovs_key_proto):
762         fields = (
763             ("src", "!6s"),
764             ("dst", "!6s"),
765         )
766
767         fields_map = (
768             (
769                 "src",
770                 "src",
771                 macstr,
772                 lambda x: int.from_bytes(x, "big"),
773                 convert_mac,
774             ),
775             (
776                 "dst",
777                 "dst",
778                 macstr,
779                 lambda x: int.from_bytes(x, "big"),
780                 convert_mac,
781             ),
782         )
783
784         def __init__(
785             self,
786             data=None,
787             offset=None,
788             parent=None,
789             length=None,
790             init=None,
791         ):
792             ovskey.ovs_key_proto.__init__(
793                 self,
794                 "eth",
795                 data=data,
796                 offset=offset,
797                 parent=parent,
798                 length=length,
799                 init=init,
800             )
801
802     class ovs_key_ipv4(ovs_key_proto):
803         fields = (
804             ("src", "!I"),
805             ("dst", "!I"),
806             ("proto", "B"),
807             ("tos", "B"),
808             ("ttl", "B"),
809             ("frag", "B"),
810         )
811
812         fields_map = (
813             (
814                 "src",
815                 "src",
816                 lambda x: str(ipaddress.IPv4Address(x)),
817                 int,
818                 convert_ipv4,
819             ),
820             (
821                 "dst",
822                 "dst",
823                 lambda x: str(ipaddress.IPv4Address(x)),
824                 int,
825                 convert_ipv4,
826             ),
827             ("proto", "proto", "%d", lambda x: int(x) if x else 0,
828                 convert_int(8)),
829             ("tos", "tos", "%d", lambda x: int(x) if x else 0,
830                 convert_int(8)),
831             ("ttl", "ttl", "%d", lambda x: int(x) if x else 0,
832                 convert_int(8)),
833             ("frag", "frag", "%d", lambda x: int(x) if x else 0,
834                 convert_int(8)),
835         )
836
837         def __init__(
838             self,
839             data=None,
840             offset=None,
841             parent=None,
842             length=None,
843             init=None,
844         ):
845             ovskey.ovs_key_proto.__init__(
846                 self,
847                 "ipv4",
848                 data=data,
849                 offset=offset,
850                 parent=parent,
851                 length=length,
852                 init=init,
853             )
854
855     class ovs_key_ipv6(ovs_key_proto):
856         fields = (
857             ("src", "!16s"),
858             ("dst", "!16s"),
859             ("label", "!I"),
860             ("proto", "B"),
861             ("tclass", "B"),
862             ("hlimit", "B"),
863             ("frag", "B"),
864         )
865
866         fields_map = (
867             (
868                 "src",
869                 "src",
870                 lambda x: str(ipaddress.IPv6Address(x)),
871                 lambda x: int.from_bytes(x, "big"),
872                 lambda x: ipaddress.IPv6Address(x),
873             ),
874             (
875                 "dst",
876                 "dst",
877                 lambda x: str(ipaddress.IPv6Address(x)),
878                 lambda x: int.from_bytes(x, "big"),
879                 lambda x: ipaddress.IPv6Address(x),
880             ),
881             ("label", "label", "%d", int),
882             ("proto", "proto", "%d", int),
883             ("tclass", "tclass", "%d", int),
884             ("hlimit", "hlimit", "%d", int),
885             ("frag", "frag", "%d", int),
886         )
887
888         def __init__(
889             self,
890             data=None,
891             offset=None,
892             parent=None,
893             length=None,
894             init=None,
895         ):
896             ovskey.ovs_key_proto.__init__(
897                 self,
898                 "ipv6",
899                 data=data,
900                 offset=offset,
901                 parent=parent,
902                 length=length,
903                 init=init,
904             )
905
906     class ovs_key_tcp(ovs_key_proto):
907         def __init__(
908             self,
909             data=None,
910             offset=None,
911             parent=None,
912             length=None,
913             init=None,
914         ):
915             ovskey.ovs_key_proto.__init__(
916                 self,
917                 "tcp",
918                 data=data,
919                 offset=offset,
920                 parent=parent,
921                 length=length,
922                 init=init,
923             )
924
925     class ovs_key_udp(ovs_key_proto):
926         def __init__(
927             self,
928             data=None,
929             offset=None,
930             parent=None,
931             length=None,
932             init=None,
933         ):
934             ovskey.ovs_key_proto.__init__(
935                 self,
936                 "udp",
937                 data=data,
938                 offset=offset,
939                 parent=parent,
940                 length=length,
941                 init=init,
942             )
943
944     class ovs_key_sctp(ovs_key_proto):
945         def __init__(
946             self,
947             data=None,
948             offset=None,
949             parent=None,
950             length=None,
951             init=None,
952         ):
953             ovskey.ovs_key_proto.__init__(
954                 self,
955                 "sctp",
956                 data=data,
957                 offset=offset,
958                 parent=parent,
959                 length=length,
960                 init=init,
961             )
962
963     class ovs_key_icmp(ovs_key_proto):
964         fields = (
965             ("type", "B"),
966             ("code", "B"),
967         )
968
969         fields_map = (
970             ("type", "type", "%d", lambda x: int(x) if x else 0),
971             ("code", "code", "%d", lambda x: int(x) if x else 0),
972         )
973
974         def __init__(
975             self,
976             data=None,
977             offset=None,
978             parent=None,
979             length=None,
980             init=None,
981         ):
982             ovskey.ovs_key_proto.__init__(
983                 self,
984                 "icmp",
985                 data=data,
986                 offset=offset,
987                 parent=parent,
988                 length=length,
989                 init=init,
990             )
991
992     class ovs_key_icmpv6(ovs_key_icmp):
993         def __init__(
994             self,
995             data=None,
996             offset=None,
997             parent=None,
998             length=None,
999             init=None,
1000         ):
1001             ovskey.ovs_key_proto.__init__(
1002                 self,
1003                 "icmpv6",
1004                 data=data,
1005                 offset=offset,
1006                 parent=parent,
1007                 length=length,
1008                 init=init,
1009             )
1010
1011     class ovs_key_arp(ovs_key_proto):
1012         fields = (
1013             ("sip", "!I"),
1014             ("tip", "!I"),
1015             ("op", "!H"),
1016             ("sha", "!6s"),
1017             ("tha", "!6s"),
1018             ("pad", "xx"),
1019         )
1020
1021         fields_map = (
1022             (
1023                 "sip",
1024                 "sip",
1025                 lambda x: str(ipaddress.IPv4Address(x)),
1026                 int,
1027                 convert_ipv4,
1028             ),
1029             (
1030                 "tip",
1031                 "tip",
1032                 lambda x: str(ipaddress.IPv4Address(x)),
1033                 int,
1034                 convert_ipv4,
1035             ),
1036             ("op", "op", "%d", lambda x: int(x) if x else 0),
1037             (
1038                 "sha",
1039                 "sha",
1040                 macstr,
1041                 lambda x: int.from_bytes(x, "big"),
1042                 convert_mac,
1043             ),
1044             (
1045                 "tha",
1046                 "tha",
1047                 macstr,
1048                 lambda x: int.from_bytes(x, "big"),
1049                 convert_mac,
1050             ),
1051         )
1052
1053         def __init__(
1054             self,
1055             data=None,
1056             offset=None,
1057             parent=None,
1058             length=None,
1059             init=None,
1060         ):
1061             ovskey.ovs_key_proto.__init__(
1062                 self,
1063                 "arp",
1064                 data=data,
1065                 offset=offset,
1066                 parent=parent,
1067                 length=length,
1068                 init=init,
1069             )
1070
1071     class ovs_key_nd(ovs_key_proto):
1072         fields = (
1073             ("target", "!16s"),
1074             ("sll", "!6s"),
1075             ("tll", "!6s"),
1076         )
1077
1078         fields_map = (
1079             (
1080                 "target",
1081                 "target",
1082                 lambda x: str(ipaddress.IPv6Address(x)),
1083                 lambda x: int.from_bytes(x, "big"),
1084             ),
1085             ("sll", "sll", macstr, lambda x: int.from_bytes(x, "big")),
1086             ("tll", "tll", macstr, lambda x: int.from_bytes(x, "big")),
1087         )
1088
1089         def __init__(
1090             self,
1091             data=None,
1092             offset=None,
1093             parent=None,
1094             length=None,
1095             init=None,
1096         ):
1097             ovskey.ovs_key_proto.__init__(
1098                 self,
1099                 "nd",
1100                 data=data,
1101                 offset=offset,
1102                 parent=parent,
1103                 length=length,
1104                 init=init,
1105             )
1106
1107     class ovs_key_ct_tuple_ipv4(ovs_key_proto):
1108         fields = (
1109             ("src", "!I"),
1110             ("dst", "!I"),
1111             ("tp_src", "!H"),
1112             ("tp_dst", "!H"),
1113             ("proto", "B"),
1114         )
1115
1116         fields_map = (
1117             (
1118                 "src",
1119                 "src",
1120                 lambda x: str(ipaddress.IPv4Address(x)),
1121                 int,
1122                 convert_ipv4,
1123             ),
1124             (
1125                 "dst",
1126                 "dst",
1127                 lambda x: str(ipaddress.IPv4Address(x)),
1128                 int,
1129                 convert_ipv4,
1130             ),
1131             ("tp_src", "tp_src", "%d", int),
1132             ("tp_dst", "tp_dst", "%d", int),
1133             ("proto", "proto", "%d", int),
1134         )
1135
1136         def __init__(
1137             self,
1138             data=None,
1139             offset=None,
1140             parent=None,
1141             length=None,
1142             init=None,
1143         ):
1144             ovskey.ovs_key_proto.__init__(
1145                 self,
1146                 "ct_tuple4",
1147                 data=data,
1148                 offset=offset,
1149                 parent=parent,
1150                 length=length,
1151                 init=init,
1152             )
1153
1154     class ovs_key_ct_tuple_ipv6(nla):
1155         fields = (
1156             ("src", "!16s"),
1157             ("dst", "!16s"),
1158             ("tp_src", "!H"),
1159             ("tp_dst", "!H"),
1160             ("proto", "B"),
1161         )
1162
1163         fields_map = (
1164             (
1165                 "src",
1166                 "src",
1167                 lambda x: str(ipaddress.IPv6Address(x)),
1168                 lambda x: int.from_bytes(x, "big", convertmac),
1169             ),
1170             (
1171                 "dst",
1172                 "dst",
1173                 lambda x: str(ipaddress.IPv6Address(x)),
1174                 lambda x: int.from_bytes(x, "big"),
1175             ),
1176             ("tp_src", "tp_src", "%d", int),
1177             ("tp_dst", "tp_dst", "%d", int),
1178             ("proto", "proto", "%d", int),
1179         )
1180
1181         def __init__(
1182             self,
1183             data=None,
1184             offset=None,
1185             parent=None,
1186             length=None,
1187             init=None,
1188         ):
1189             ovskey.ovs_key_proto.__init__(
1190                 self,
1191                 "ct_tuple6",
1192                 data=data,
1193                 offset=offset,
1194                 parent=parent,
1195                 length=length,
1196                 init=init,
1197             )
1198
1199     class ovs_key_mpls(nla):
1200         fields = (("lse", ">I"),)
1201
1202     def parse(self, flowstr, mask=None):
1203         for field in (
1204             ("OVS_KEY_ATTR_PRIORITY", "skb_priority", intparse),
1205             ("OVS_KEY_ATTR_SKB_MARK", "skb_mark", intparse),
1206             ("OVS_KEY_ATTR_RECIRC_ID", "recirc_id", intparse),
1207             ("OVS_KEY_ATTR_DP_HASH", "dp_hash", intparse),
1208             ("OVS_KEY_ATTR_CT_STATE", "ct_state", parse_ct_state),
1209             ("OVS_KEY_ATTR_CT_ZONE", "ct_zone", intparse),
1210             ("OVS_KEY_ATTR_CT_MARK", "ct_mark", intparse),
1211             ("OVS_KEY_ATTR_IN_PORT", "in_port", intparse),
1212             (
1213                 "OVS_KEY_ATTR_ETHERNET",
1214                 "eth",
1215                 ovskey.ethaddr,
1216             ),
1217             (
1218                 "OVS_KEY_ATTR_ETHERTYPE",
1219                 "eth_type",
1220                 lambda x: intparse(x, "0xffff"),
1221             ),
1222             (
1223                 "OVS_KEY_ATTR_IPV4",
1224                 "ipv4",
1225                 ovskey.ovs_key_ipv4,
1226             ),
1227             (
1228                 "OVS_KEY_ATTR_IPV6",
1229                 "ipv6",
1230                 ovskey.ovs_key_ipv6,
1231             ),
1232             (
1233                 "OVS_KEY_ATTR_ARP",
1234                 "arp",
1235                 ovskey.ovs_key_arp,
1236             ),
1237             (
1238                 "OVS_KEY_ATTR_TCP",
1239                 "tcp",
1240                 ovskey.ovs_key_tcp,
1241             ),
1242             (
1243                 "OVS_KEY_ATTR_UDP",
1244                 "udp",
1245                 ovskey.ovs_key_udp,
1246             ),
1247             (
1248                 "OVS_KEY_ATTR_ICMP",
1249                 "icmp",
1250                 ovskey.ovs_key_icmp,
1251             ),
1252             (
1253                 "OVS_KEY_ATTR_TCP_FLAGS",
1254                 "tcp_flags",
1255                 lambda x: parse_flags(x, None),
1256             ),
1257         ):
1258             fld = field[1] + "("
1259             if not flowstr.startswith(fld):
1260                 continue
1261
1262             if not isinstance(field[2], types.FunctionType):
1263                 nk = field[2]()
1264                 flowstr, k, m = nk.parse(flowstr, field[2])
1265             else:
1266                 flowstr = flowstr[len(fld) :]
1267                 flowstr, k, m = field[2](flowstr)
1268
1269             if m and mask is not None:
1270                 mask["attrs"].append([field[0], m])
1271             self["attrs"].append([field[0], k])
1272
1273             flowstr = flowstr[strspn(flowstr, "),") :]
1274
1275         return flowstr
1276
1277     def dpstr(self, mask=None, more=False):
1278         print_str = ""
1279
1280         for field in (
1281             (
1282                 "OVS_KEY_ATTR_PRIORITY",
1283                 "skb_priority",
1284                 "%d",
1285                 lambda x: False,
1286                 True,
1287             ),
1288             (
1289                 "OVS_KEY_ATTR_SKB_MARK",
1290                 "skb_mark",
1291                 "%d",
1292                 lambda x: False,
1293                 True,
1294             ),
1295             (
1296                 "OVS_KEY_ATTR_RECIRC_ID",
1297                 "recirc_id",
1298                 "0x%08X",
1299                 lambda x: False,
1300                 True,
1301             ),
1302             (
1303                 "OVS_KEY_ATTR_DP_HASH",
1304                 "dp_hash",
1305                 "0x%08X",
1306                 lambda x: False,
1307                 True,
1308             ),
1309             (
1310                 "OVS_KEY_ATTR_CT_STATE",
1311                 "ct_state",
1312                 "0x%04x",
1313                 lambda x: False,
1314                 True,
1315             ),
1316             (
1317                 "OVS_KEY_ATTR_CT_ZONE",
1318                 "ct_zone",
1319                 "0x%04x",
1320                 lambda x: False,
1321                 True,
1322             ),
1323             (
1324                 "OVS_KEY_ATTR_CT_MARK",
1325                 "ct_mark",
1326                 "0x%08x",
1327                 lambda x: False,
1328                 True,
1329             ),
1330             (
1331                 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4",
1332                 None,
1333                 None,
1334                 False,
1335                 False,
1336             ),
1337             (
1338                 "OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6",
1339                 None,
1340                 None,
1341                 False,
1342                 False,
1343             ),
1344             (
1345                 "OVS_KEY_ATTR_IN_PORT",
1346                 "in_port",
1347                 "%d",
1348                 lambda x: True,
1349                 True,
1350             ),
1351             ("OVS_KEY_ATTR_ETHERNET", None, None, False, False),
1352             (
1353                 "OVS_KEY_ATTR_ETHERTYPE",
1354                 "eth_type",
1355                 "0x%04x",
1356                 lambda x: int(x) == 0xFFFF,
1357                 True,
1358             ),
1359             ("OVS_KEY_ATTR_IPV4", None, None, False, False),
1360             ("OVS_KEY_ATTR_IPV6", None, None, False, False),
1361             ("OVS_KEY_ATTR_ARP", None, None, False, False),
1362             ("OVS_KEY_ATTR_TCP", None, None, False, False),
1363             (
1364                 "OVS_KEY_ATTR_TCP_FLAGS",
1365                 "tcp_flags",
1366                 "0x%04x",
1367                 lambda x: False,
1368                 True,
1369             ),
1370             ("OVS_KEY_ATTR_UDP", None, None, False, False),
1371             ("OVS_KEY_ATTR_SCTP", None, None, False, False),
1372             ("OVS_KEY_ATTR_ICMP", None, None, False, False),
1373             ("OVS_KEY_ATTR_ICMPV6", None, None, False, False),
1374             ("OVS_KEY_ATTR_ND", None, None, False, False),
1375         ):
1376             v = self.get_attr(field[0])
1377             if v is not None:
1378                 m = None if mask is None else mask.get_attr(field[0])
1379                 if field[4] is False:
1380                     print_str += v.dpstr(m, more)
1381                     print_str += ","
1382                 else:
1383                     if m is None or field[3](m):
1384                         print_str += field[1] + "("
1385                         print_str += field[2] % v
1386                         print_str += "),"
1387                     elif more or m != 0:
1388                         print_str += field[1] + "("
1389                         print_str += (field[2] % v) + "/" + (field[2] % m)
1390                         print_str += "),"
1391
1392         return print_str
1393
1394
1395 class OvsPacket(GenericNetlinkSocket):
1396     OVS_PACKET_CMD_MISS = 1  # Flow table miss
1397     OVS_PACKET_CMD_ACTION = 2  # USERSPACE action
1398     OVS_PACKET_CMD_EXECUTE = 3  # Apply actions to packet
1399
1400     class ovs_packet_msg(ovs_dp_msg):
1401         nla_map = (
1402             ("OVS_PACKET_ATTR_UNSPEC", "none"),
1403             ("OVS_PACKET_ATTR_PACKET", "array(uint8)"),
1404             ("OVS_PACKET_ATTR_KEY", "ovskey"),
1405             ("OVS_PACKET_ATTR_ACTIONS", "ovsactions"),
1406             ("OVS_PACKET_ATTR_USERDATA", "none"),
1407             ("OVS_PACKET_ATTR_EGRESS_TUN_KEY", "none"),
1408             ("OVS_PACKET_ATTR_UNUSED1", "none"),
1409             ("OVS_PACKET_ATTR_UNUSED2", "none"),
1410             ("OVS_PACKET_ATTR_PROBE", "none"),
1411             ("OVS_PACKET_ATTR_MRU", "uint16"),
1412             ("OVS_PACKET_ATTR_LEN", "uint32"),
1413             ("OVS_PACKET_ATTR_HASH", "uint64"),
1414         )
1415
1416     def __init__(self):
1417         GenericNetlinkSocket.__init__(self)
1418         self.bind(OVS_PACKET_FAMILY, OvsPacket.ovs_packet_msg)
1419
1420     def upcall_handler(self, up=None):
1421         print("listening on upcall packet handler:", self.epid)
1422         while True:
1423             try:
1424                 msgs = self.get()
1425                 for msg in msgs:
1426                     if not up:
1427                         continue
1428                     if msg["cmd"] == OvsPacket.OVS_PACKET_CMD_MISS:
1429                         up.miss(msg)
1430                     elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_ACTION:
1431                         up.action(msg)
1432                     elif msg["cmd"] == OvsPacket.OVS_PACKET_CMD_EXECUTE:
1433                         up.execute(msg)
1434                     else:
1435                         print("Unkonwn cmd: %d" % msg["cmd"])
1436             except NetlinkError as ne:
1437                 raise ne
1438
1439
1440 class OvsDatapath(GenericNetlinkSocket):
1441     OVS_DP_F_VPORT_PIDS = 1 << 1
1442     OVS_DP_F_DISPATCH_UPCALL_PER_CPU = 1 << 3
1443
1444     class dp_cmd_msg(ovs_dp_msg):
1445         """
1446         Message class that will be used to communicate with the kernel module.
1447         """
1448
1449         nla_map = (
1450             ("OVS_DP_ATTR_UNSPEC", "none"),
1451             ("OVS_DP_ATTR_NAME", "asciiz"),
1452             ("OVS_DP_ATTR_UPCALL_PID", "array(uint32)"),
1453             ("OVS_DP_ATTR_STATS", "dpstats"),
1454             ("OVS_DP_ATTR_MEGAFLOW_STATS", "megaflowstats"),
1455             ("OVS_DP_ATTR_USER_FEATURES", "uint32"),
1456             ("OVS_DP_ATTR_PAD", "none"),
1457             ("OVS_DP_ATTR_MASKS_CACHE_SIZE", "uint32"),
1458             ("OVS_DP_ATTR_PER_CPU_PIDS", "array(uint32)"),
1459         )
1460
1461         class dpstats(nla):
1462             fields = (
1463                 ("hit", "=Q"),
1464                 ("missed", "=Q"),
1465                 ("lost", "=Q"),
1466                 ("flows", "=Q"),
1467             )
1468
1469         class megaflowstats(nla):
1470             fields = (
1471                 ("mask_hit", "=Q"),
1472                 ("masks", "=I"),
1473                 ("padding", "=I"),
1474                 ("cache_hits", "=Q"),
1475                 ("pad1", "=Q"),
1476             )
1477
1478     def __init__(self):
1479         GenericNetlinkSocket.__init__(self)
1480         self.bind(OVS_DATAPATH_FAMILY, OvsDatapath.dp_cmd_msg)
1481
1482     def info(self, dpname, ifindex=0):
1483         msg = OvsDatapath.dp_cmd_msg()
1484         msg["cmd"] = OVS_DP_CMD_GET
1485         msg["version"] = OVS_DATAPATH_VERSION
1486         msg["reserved"] = 0
1487         msg["dpifindex"] = ifindex
1488         msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1489
1490         try:
1491             reply = self.nlm_request(
1492                 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
1493             )
1494             reply = reply[0]
1495         except NetlinkError as ne:
1496             if ne.code == errno.ENODEV:
1497                 reply = None
1498             else:
1499                 raise ne
1500
1501         return reply
1502
1503     def create(
1504         self, dpname, shouldUpcall=False, versionStr=None, p=OvsPacket()
1505     ):
1506         msg = OvsDatapath.dp_cmd_msg()
1507         msg["cmd"] = OVS_DP_CMD_NEW
1508         if versionStr is None:
1509             msg["version"] = OVS_DATAPATH_VERSION
1510         else:
1511             msg["version"] = int(versionStr.split(":")[0], 0)
1512         msg["reserved"] = 0
1513         msg["dpifindex"] = 0
1514         msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1515
1516         dpfeatures = 0
1517         if versionStr is not None and versionStr.find(":") != -1:
1518             dpfeatures = int(versionStr.split(":")[1], 0)
1519         else:
1520             if versionStr is None or versionStr.find(":") == -1:
1521                 dpfeatures |= OvsDatapath.OVS_DP_F_DISPATCH_UPCALL_PER_CPU
1522                 dpfeatures &= ~OvsDatapath.OVS_DP_F_VPORT_PIDS
1523
1524             nproc = multiprocessing.cpu_count()
1525             procarray = []
1526             for i in range(1, nproc):
1527                 procarray += [int(p.epid)]
1528             msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", procarray])
1529         msg["attrs"].append(["OVS_DP_ATTR_USER_FEATURES", dpfeatures])
1530         if not shouldUpcall:
1531             msg["attrs"].append(["OVS_DP_ATTR_UPCALL_PID", [0]])
1532
1533         try:
1534             reply = self.nlm_request(
1535                 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1536             )
1537             reply = reply[0]
1538         except NetlinkError as ne:
1539             if ne.code == errno.EEXIST:
1540                 reply = None
1541             else:
1542                 raise ne
1543
1544         return reply
1545
1546     def destroy(self, dpname):
1547         msg = OvsDatapath.dp_cmd_msg()
1548         msg["cmd"] = OVS_DP_CMD_DEL
1549         msg["version"] = OVS_DATAPATH_VERSION
1550         msg["reserved"] = 0
1551         msg["dpifindex"] = 0
1552         msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
1553
1554         try:
1555             reply = self.nlm_request(
1556                 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1557             )
1558             reply = reply[0]
1559         except NetlinkError as ne:
1560             if ne.code == errno.ENODEV:
1561                 reply = None
1562             else:
1563                 raise ne
1564
1565         return reply
1566
1567
1568 class OvsVport(GenericNetlinkSocket):
1569     OVS_VPORT_TYPE_NETDEV = 1
1570     OVS_VPORT_TYPE_INTERNAL = 2
1571     OVS_VPORT_TYPE_GRE = 3
1572     OVS_VPORT_TYPE_VXLAN = 4
1573     OVS_VPORT_TYPE_GENEVE = 5
1574
1575     class ovs_vport_msg(ovs_dp_msg):
1576         nla_map = (
1577             ("OVS_VPORT_ATTR_UNSPEC", "none"),
1578             ("OVS_VPORT_ATTR_PORT_NO", "uint32"),
1579             ("OVS_VPORT_ATTR_TYPE", "uint32"),
1580             ("OVS_VPORT_ATTR_NAME", "asciiz"),
1581             ("OVS_VPORT_ATTR_OPTIONS", "none"),
1582             ("OVS_VPORT_ATTR_UPCALL_PID", "array(uint32)"),
1583             ("OVS_VPORT_ATTR_STATS", "vportstats"),
1584             ("OVS_VPORT_ATTR_PAD", "none"),
1585             ("OVS_VPORT_ATTR_IFINDEX", "uint32"),
1586             ("OVS_VPORT_ATTR_NETNSID", "uint32"),
1587         )
1588
1589         class vportstats(nla):
1590             fields = (
1591                 ("rx_packets", "=Q"),
1592                 ("tx_packets", "=Q"),
1593                 ("rx_bytes", "=Q"),
1594                 ("tx_bytes", "=Q"),
1595                 ("rx_errors", "=Q"),
1596                 ("tx_errors", "=Q"),
1597                 ("rx_dropped", "=Q"),
1598                 ("tx_dropped", "=Q"),
1599             )
1600
1601     def type_to_str(vport_type):
1602         if vport_type == OvsVport.OVS_VPORT_TYPE_NETDEV:
1603             return "netdev"
1604         elif vport_type == OvsVport.OVS_VPORT_TYPE_INTERNAL:
1605             return "internal"
1606         elif vport_type == OvsVport.OVS_VPORT_TYPE_GRE:
1607             return "gre"
1608         elif vport_type == OvsVport.OVS_VPORT_TYPE_VXLAN:
1609             return "vxlan"
1610         elif vport_type == OvsVport.OVS_VPORT_TYPE_GENEVE:
1611             return "geneve"
1612         raise ValueError("Unknown vport type:%d" % vport_type)
1613
1614     def str_to_type(vport_type):
1615         if vport_type == "netdev":
1616             return OvsVport.OVS_VPORT_TYPE_NETDEV
1617         elif vport_type == "internal":
1618             return OvsVport.OVS_VPORT_TYPE_INTERNAL
1619         elif vport_type == "gre":
1620             return OvsVport.OVS_VPORT_TYPE_INTERNAL
1621         elif vport_type == "vxlan":
1622             return OvsVport.OVS_VPORT_TYPE_VXLAN
1623         elif vport_type == "geneve":
1624             return OvsVport.OVS_VPORT_TYPE_GENEVE
1625         raise ValueError("Unknown vport type: '%s'" % vport_type)
1626
1627     def __init__(self, packet=OvsPacket()):
1628         GenericNetlinkSocket.__init__(self)
1629         self.bind(OVS_VPORT_FAMILY, OvsVport.ovs_vport_msg)
1630         self.upcall_packet = packet
1631
1632     def info(self, vport_name, dpifindex=0, portno=None):
1633         msg = OvsVport.ovs_vport_msg()
1634
1635         msg["cmd"] = OVS_VPORT_CMD_GET
1636         msg["version"] = OVS_DATAPATH_VERSION
1637         msg["reserved"] = 0
1638         msg["dpifindex"] = dpifindex
1639
1640         if portno is None:
1641             msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_name])
1642         else:
1643             msg["attrs"].append(["OVS_VPORT_ATTR_PORT_NO", portno])
1644
1645         try:
1646             reply = self.nlm_request(
1647                 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST
1648             )
1649             reply = reply[0]
1650         except NetlinkError as ne:
1651             if ne.code == errno.ENODEV:
1652                 reply = None
1653             else:
1654                 raise ne
1655         return reply
1656
1657     def attach(self, dpindex, vport_ifname, ptype):
1658         msg = OvsVport.ovs_vport_msg()
1659
1660         msg["cmd"] = OVS_VPORT_CMD_NEW
1661         msg["version"] = OVS_DATAPATH_VERSION
1662         msg["reserved"] = 0
1663         msg["dpifindex"] = dpindex
1664         port_type = OvsVport.str_to_type(ptype)
1665
1666         msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type])
1667         msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1668         msg["attrs"].append(
1669             ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]]
1670         )
1671
1672         try:
1673             reply = self.nlm_request(
1674                 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1675             )
1676             reply = reply[0]
1677         except NetlinkError as ne:
1678             if ne.code == errno.EEXIST:
1679                 reply = None
1680             else:
1681                 raise ne
1682         return reply
1683
1684     def reset_upcall(self, dpindex, vport_ifname, p=None):
1685         msg = OvsVport.ovs_vport_msg()
1686
1687         msg["cmd"] = OVS_VPORT_CMD_SET
1688         msg["version"] = OVS_DATAPATH_VERSION
1689         msg["reserved"] = 0
1690         msg["dpifindex"] = dpindex
1691         msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1692
1693         if p == None:
1694             p = self.upcall_packet
1695         else:
1696             self.upcall_packet = p
1697
1698         msg["attrs"].append(["OVS_VPORT_ATTR_UPCALL_PID", [p.epid]])
1699
1700         try:
1701             reply = self.nlm_request(
1702                 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1703             )
1704             reply = reply[0]
1705         except NetlinkError as ne:
1706             raise ne
1707         return reply
1708
1709     def detach(self, dpindex, vport_ifname):
1710         msg = OvsVport.ovs_vport_msg()
1711
1712         msg["cmd"] = OVS_VPORT_CMD_DEL
1713         msg["version"] = OVS_DATAPATH_VERSION
1714         msg["reserved"] = 0
1715         msg["dpifindex"] = dpindex
1716         msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
1717
1718         try:
1719             reply = self.nlm_request(
1720                 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
1721             )
1722             reply = reply[0]
1723         except NetlinkError as ne:
1724             if ne.code == errno.ENODEV:
1725                 reply = None
1726             else:
1727                 raise ne
1728         return reply
1729
1730     def upcall_handler(self, handler=None):
1731         self.upcall_packet.upcall_handler(handler)
1732
1733
1734 class OvsFlow(GenericNetlinkSocket):
1735     class ovs_flow_msg(ovs_dp_msg):
1736         nla_map = (
1737             ("OVS_FLOW_ATTR_UNSPEC", "none"),
1738             ("OVS_FLOW_ATTR_KEY", "ovskey"),
1739             ("OVS_FLOW_ATTR_ACTIONS", "ovsactions"),
1740             ("OVS_FLOW_ATTR_STATS", "flowstats"),
1741             ("OVS_FLOW_ATTR_TCP_FLAGS", "uint8"),
1742             ("OVS_FLOW_ATTR_USED", "uint64"),
1743             ("OVS_FLOW_ATTR_CLEAR", "none"),
1744             ("OVS_FLOW_ATTR_MASK", "ovskey"),
1745             ("OVS_FLOW_ATTR_PROBE", "none"),
1746             ("OVS_FLOW_ATTR_UFID", "array(uint32)"),
1747             ("OVS_FLOW_ATTR_UFID_FLAGS", "uint32"),
1748         )
1749
1750         class flowstats(nla):
1751             fields = (
1752                 ("packets", "=Q"),
1753                 ("bytes", "=Q"),
1754             )
1755
1756         def dpstr(self, more=False):
1757             ufid = self.get_attr("OVS_FLOW_ATTR_UFID")
1758             ufid_str = ""
1759             if ufid is not None:
1760                 ufid_str = (
1761                     "ufid:{:08x}-{:04x}-{:04x}-{:04x}-{:04x}{:08x}".format(
1762                         ufid[0],
1763                         ufid[1] >> 16,
1764                         ufid[1] & 0xFFFF,
1765                         ufid[2] >> 16,
1766                         ufid[2] & 0,
1767                         ufid[3],
1768                     )
1769                 )
1770
1771             key_field = self.get_attr("OVS_FLOW_ATTR_KEY")
1772             keymsg = None
1773             if key_field is not None:
1774                 keymsg = key_field
1775
1776             mask_field = self.get_attr("OVS_FLOW_ATTR_MASK")
1777             maskmsg = None
1778             if mask_field is not None:
1779                 maskmsg = mask_field
1780
1781             acts_field = self.get_attr("OVS_FLOW_ATTR_ACTIONS")
1782             actsmsg = None
1783             if acts_field is not None:
1784                 actsmsg = acts_field
1785
1786             print_str = ""
1787
1788             if more:
1789                 print_str += ufid_str + ","
1790
1791             if keymsg is not None:
1792                 print_str += keymsg.dpstr(maskmsg, more)
1793
1794             stats = self.get_attr("OVS_FLOW_ATTR_STATS")
1795             if stats is None:
1796                 print_str += " packets:0, bytes:0,"
1797             else:
1798                 print_str += " packets:%d, bytes:%d," % (
1799                     stats["packets"],
1800                     stats["bytes"],
1801                 )
1802
1803             used = self.get_attr("OVS_FLOW_ATTR_USED")
1804             print_str += " used:"
1805             if used is None:
1806                 print_str += "never,"
1807             else:
1808                 used_time = int(used)
1809                 cur_time_sec = time.clock_gettime(time.CLOCK_MONOTONIC)
1810                 used_time = (cur_time_sec * 1000) - used_time
1811                 print_str += "{}s,".format(used_time / 1000)
1812
1813             print_str += " actions:"
1814             if (
1815                 actsmsg is None
1816                 or "attrs" not in actsmsg
1817                 or len(actsmsg["attrs"]) == 0
1818             ):
1819                 print_str += "drop"
1820             else:
1821                 print_str += actsmsg.dpstr(more)
1822
1823             return print_str
1824
1825         def parse(self, flowstr, actstr, dpidx=0):
1826             OVS_UFID_F_OMIT_KEY = 1 << 0
1827             OVS_UFID_F_OMIT_MASK = 1 << 1
1828             OVS_UFID_F_OMIT_ACTIONS = 1 << 2
1829
1830             self["cmd"] = 0
1831             self["version"] = 0
1832             self["reserved"] = 0
1833             self["dpifindex"] = 0
1834
1835             if flowstr.startswith("ufid:"):
1836                 count = 5
1837                 while flowstr[count] != ",":
1838                     count += 1
1839                 ufidstr = flowstr[5:count]
1840                 flowstr = flowstr[count + 1 :]
1841             else:
1842                 ufidstr = str(uuid.uuid4())
1843             uuidRawObj = uuid.UUID(ufidstr).fields
1844
1845             self["attrs"].append(
1846                 [
1847                     "OVS_FLOW_ATTR_UFID",
1848                     [
1849                         uuidRawObj[0],
1850                         uuidRawObj[1] << 16 | uuidRawObj[2],
1851                         uuidRawObj[3] << 24
1852                         | uuidRawObj[4] << 16
1853                         | uuidRawObj[5] & (0xFF << 32) >> 32,
1854                         uuidRawObj[5] & (0xFFFFFFFF),
1855                     ],
1856                 ]
1857             )
1858             self["attrs"].append(
1859                 [
1860                     "OVS_FLOW_ATTR_UFID_FLAGS",
1861                     int(
1862                         OVS_UFID_F_OMIT_KEY
1863                         | OVS_UFID_F_OMIT_MASK
1864                         | OVS_UFID_F_OMIT_ACTIONS
1865                     ),
1866                 ]
1867             )
1868
1869             k = ovskey()
1870             m = ovskey()
1871             k.parse(flowstr, m)
1872             self["attrs"].append(["OVS_FLOW_ATTR_KEY", k])
1873             self["attrs"].append(["OVS_FLOW_ATTR_MASK", m])
1874
1875             a = ovsactions()
1876             a.parse(actstr)
1877             self["attrs"].append(["OVS_FLOW_ATTR_ACTIONS", a])
1878
1879     def __init__(self):
1880         GenericNetlinkSocket.__init__(self)
1881
1882         self.bind(OVS_FLOW_FAMILY, OvsFlow.ovs_flow_msg)
1883
1884     def add_flow(self, dpifindex, flowmsg):
1885         """
1886         Send a new flow message to the kernel.
1887
1888         dpifindex should be a valid datapath obtained by calling
1889         into the OvsDatapath lookup
1890
1891         flowmsg is a flow object obtained by calling a dpparse
1892         """
1893
1894         flowmsg["cmd"] = OVS_FLOW_CMD_NEW
1895         flowmsg["version"] = OVS_DATAPATH_VERSION
1896         flowmsg["reserved"] = 0
1897         flowmsg["dpifindex"] = dpifindex
1898
1899         try:
1900             reply = self.nlm_request(
1901                 flowmsg,
1902                 msg_type=self.prid,
1903                 msg_flags=NLM_F_REQUEST | NLM_F_ACK,
1904             )
1905             reply = reply[0]
1906         except NetlinkError as ne:
1907             print(flowmsg)
1908             raise ne
1909         return reply
1910
1911     def del_flows(self, dpifindex):
1912         """
1913         Send a del message to the kernel that will drop all flows.
1914
1915         dpifindex should be a valid datapath obtained by calling
1916         into the OvsDatapath lookup
1917         """
1918
1919         flowmsg = OvsFlow.ovs_flow_msg()
1920         flowmsg["cmd"] = OVS_FLOW_CMD_DEL
1921         flowmsg["version"] = OVS_DATAPATH_VERSION
1922         flowmsg["reserved"] = 0
1923         flowmsg["dpifindex"] = dpifindex
1924
1925         try:
1926             reply = self.nlm_request(
1927                 flowmsg,
1928                 msg_type=self.prid,
1929                 msg_flags=NLM_F_REQUEST | NLM_F_ACK,
1930             )
1931             reply = reply[0]
1932         except NetlinkError as ne:
1933             print(flowmsg)
1934             raise ne
1935         return reply
1936
1937     def dump(self, dpifindex, flowspec=None):
1938         """
1939         Returns a list of messages containing flows.
1940
1941         dpifindex should be a valid datapath obtained by calling
1942         into the OvsDatapath lookup
1943
1944         flowpsec is a string which represents a flow in the dpctl
1945         format.
1946         """
1947         msg = OvsFlow.ovs_flow_msg()
1948
1949         msg["cmd"] = OVS_FLOW_CMD_GET
1950         msg["version"] = OVS_DATAPATH_VERSION
1951         msg["reserved"] = 0
1952         msg["dpifindex"] = dpifindex
1953
1954         msg_flags = NLM_F_REQUEST | NLM_F_ACK
1955         if flowspec is None:
1956             msg_flags |= NLM_F_DUMP
1957         rep = None
1958
1959         try:
1960             rep = self.nlm_request(
1961                 msg,
1962                 msg_type=self.prid,
1963                 msg_flags=msg_flags,
1964             )
1965         except NetlinkError as ne:
1966             raise ne
1967         return rep
1968
1969     def miss(self, packetmsg):
1970         seq = packetmsg["header"]["sequence_number"]
1971         keystr = "(none)"
1972         key_field = packetmsg.get_attr("OVS_PACKET_ATTR_KEY")
1973         if key_field is not None:
1974             keystr = key_field.dpstr(None, True)
1975
1976         pktdata = packetmsg.get_attr("OVS_PACKET_ATTR_PACKET")
1977         pktpres = "yes" if pktdata is not None else "no"
1978
1979         print("MISS upcall[%d/%s]: %s" % (seq, pktpres, keystr), flush=True)
1980
1981     def execute(self, packetmsg):
1982         print("userspace execute command")
1983
1984     def action(self, packetmsg):
1985         print("userspace action command")
1986
1987
1988 def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()):
1989     dp_name = dp_lookup_rep.get_attr("OVS_DP_ATTR_NAME")
1990     base_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_STATS")
1991     megaflow_stats = dp_lookup_rep.get_attr("OVS_DP_ATTR_MEGAFLOW_STATS")
1992     user_features = dp_lookup_rep.get_attr("OVS_DP_ATTR_USER_FEATURES")
1993     masks_cache_size = dp_lookup_rep.get_attr("OVS_DP_ATTR_MASKS_CACHE_SIZE")
1994
1995     print("%s:" % dp_name)
1996     print(
1997         "  lookups: hit:%d missed:%d lost:%d"
1998         % (base_stats["hit"], base_stats["missed"], base_stats["lost"])
1999     )
2000     print("  flows:%d" % base_stats["flows"])
2001     pkts = base_stats["hit"] + base_stats["missed"]
2002     avg = (megaflow_stats["mask_hit"] / pkts) if pkts != 0 else 0.0
2003     print(
2004         "  masks: hit:%d total:%d hit/pkt:%f"
2005         % (megaflow_stats["mask_hit"], megaflow_stats["masks"], avg)
2006     )
2007     print("  caches:")
2008     print("    masks-cache: size:%d" % masks_cache_size)
2009
2010     if user_features is not None:
2011         print("  features: 0x%X" % user_features)
2012
2013     # port print out
2014     for iface in ndb.interfaces:
2015         rep = vpl.info(iface.ifname, ifindex)
2016         if rep is not None:
2017             print(
2018                 "  port %d: %s (%s)"
2019                 % (
2020                     rep.get_attr("OVS_VPORT_ATTR_PORT_NO"),
2021                     rep.get_attr("OVS_VPORT_ATTR_NAME"),
2022                     OvsVport.type_to_str(rep.get_attr("OVS_VPORT_ATTR_TYPE")),
2023                 )
2024             )
2025
2026
2027 def main(argv):
2028     nlmsg_atoms.ovskey = ovskey
2029     nlmsg_atoms.ovsactions = ovsactions
2030
2031     # version check for pyroute2
2032     prverscheck = pyroute2.__version__.split(".")
2033     if int(prverscheck[0]) == 0 and int(prverscheck[1]) < 6:
2034         print("Need to upgrade the python pyroute2 package to >= 0.6.")
2035         sys.exit(0)
2036
2037     parser = argparse.ArgumentParser()
2038     parser.add_argument(
2039         "-v",
2040         "--verbose",
2041         action="count",
2042         help="Increment 'verbose' output counter.",
2043         default=0,
2044     )
2045     subparsers = parser.add_subparsers()
2046
2047     showdpcmd = subparsers.add_parser("show")
2048     showdpcmd.add_argument(
2049         "showdp", metavar="N", type=str, nargs="?", help="Datapath Name"
2050     )
2051
2052     adddpcmd = subparsers.add_parser("add-dp")
2053     adddpcmd.add_argument("adddp", help="Datapath Name")
2054     adddpcmd.add_argument(
2055         "-u",
2056         "--upcall",
2057         action="store_true",
2058         help="Leave open a reader for upcalls",
2059     )
2060     adddpcmd.add_argument(
2061         "-V",
2062         "--versioning",
2063         required=False,
2064         help="Specify a custom version / feature string",
2065     )
2066
2067     deldpcmd = subparsers.add_parser("del-dp")
2068     deldpcmd.add_argument("deldp", help="Datapath Name")
2069
2070     addifcmd = subparsers.add_parser("add-if")
2071     addifcmd.add_argument("dpname", help="Datapath Name")
2072     addifcmd.add_argument("addif", help="Interface name for adding")
2073     addifcmd.add_argument(
2074         "-u",
2075         "--upcall",
2076         action="store_true",
2077         help="Leave open a reader for upcalls",
2078     )
2079     addifcmd.add_argument(
2080         "-t",
2081         "--ptype",
2082         type=str,
2083         default="netdev",
2084         choices=["netdev", "internal"],
2085         help="Interface type (default netdev)",
2086     )
2087     delifcmd = subparsers.add_parser("del-if")
2088     delifcmd.add_argument("dpname", help="Datapath Name")
2089     delifcmd.add_argument("delif", help="Interface name for adding")
2090
2091     dumpflcmd = subparsers.add_parser("dump-flows")
2092     dumpflcmd.add_argument("dumpdp", help="Datapath Name")
2093
2094     addflcmd = subparsers.add_parser("add-flow")
2095     addflcmd.add_argument("flbr", help="Datapath name")
2096     addflcmd.add_argument("flow", help="Flow specification")
2097     addflcmd.add_argument("acts", help="Flow actions")
2098
2099     delfscmd = subparsers.add_parser("del-flows")
2100     delfscmd.add_argument("flsbr", help="Datapath name")
2101
2102     args = parser.parse_args()
2103
2104     if args.verbose > 0:
2105         if args.verbose > 1:
2106             logging.basicConfig(level=logging.DEBUG)
2107
2108     ovspk = OvsPacket()
2109     ovsdp = OvsDatapath()
2110     ovsvp = OvsVport(ovspk)
2111     ovsflow = OvsFlow()
2112     ndb = NDB()
2113
2114     if hasattr(args, "showdp"):
2115         found = False
2116         for iface in ndb.interfaces:
2117             rep = None
2118             if args.showdp is None:
2119                 rep = ovsdp.info(iface.ifname, 0)
2120             elif args.showdp == iface.ifname:
2121                 rep = ovsdp.info(iface.ifname, 0)
2122
2123             if rep is not None:
2124                 found = True
2125                 print_ovsdp_full(rep, iface.index, ndb, ovsvp)
2126
2127         if not found:
2128             msg = "No DP found"
2129             if args.showdp is not None:
2130                 msg += ":'%s'" % args.showdp
2131             print(msg)
2132     elif hasattr(args, "adddp"):
2133         rep = ovsdp.create(args.adddp, args.upcall, args.versioning, ovspk)
2134         if rep is None:
2135             print("DP '%s' already exists" % args.adddp)
2136         else:
2137             print("DP '%s' added" % args.adddp)
2138         if args.upcall:
2139             ovspk.upcall_handler(ovsflow)
2140     elif hasattr(args, "deldp"):
2141         ovsdp.destroy(args.deldp)
2142     elif hasattr(args, "addif"):
2143         rep = ovsdp.info(args.dpname, 0)
2144         if rep is None:
2145             print("DP '%s' not found." % args.dpname)
2146             return 1
2147         dpindex = rep["dpifindex"]
2148         rep = ovsvp.attach(rep["dpifindex"], args.addif, args.ptype)
2149         msg = "vport '%s'" % args.addif
2150         if rep and rep["header"]["error"] is None:
2151             msg += " added."
2152         else:
2153             msg += " failed to add."
2154         if args.upcall:
2155             if rep is None:
2156                 rep = ovsvp.reset_upcall(dpindex, args.addif, ovspk)
2157             ovsvp.upcall_handler(ovsflow)
2158     elif hasattr(args, "delif"):
2159         rep = ovsdp.info(args.dpname, 0)
2160         if rep is None:
2161             print("DP '%s' not found." % args.dpname)
2162             return 1
2163         rep = ovsvp.detach(rep["dpifindex"], args.delif)
2164         msg = "vport '%s'" % args.delif
2165         if rep and rep["header"]["error"] is None:
2166             msg += " removed."
2167         else:
2168             msg += " failed to remove."
2169     elif hasattr(args, "dumpdp"):
2170         rep = ovsdp.info(args.dumpdp, 0)
2171         if rep is None:
2172             print("DP '%s' not found." % args.dumpdp)
2173             return 1
2174         rep = ovsflow.dump(rep["dpifindex"])
2175         for flow in rep:
2176             print(flow.dpstr(True if args.verbose > 0 else False))
2177     elif hasattr(args, "flbr"):
2178         rep = ovsdp.info(args.flbr, 0)
2179         if rep is None:
2180             print("DP '%s' not found." % args.flbr)
2181             return 1
2182         flow = OvsFlow.ovs_flow_msg()
2183         flow.parse(args.flow, args.acts, rep["dpifindex"])
2184         ovsflow.add_flow(rep["dpifindex"], flow)
2185     elif hasattr(args, "flsbr"):
2186         rep = ovsdp.info(args.flsbr, 0)
2187         if rep is None:
2188             print("DP '%s' not found." % args.flsbr)
2189         ovsflow.del_flows(rep["dpifindex"])
2190
2191     return 0
2192
2193
2194 if __name__ == "__main__":
2195     sys.exit(main(sys.argv))