@@ -161,6 +161,24 @@ def parse_priority(self):
161161 E_PARSER , "'{}' is not a valid priority" .format (priority )
162162 )
163163
164+ def parse_cookie (self ):
165+ COOKIE_REGEX = re .compile (
166+ r"^0x0*([0-9a-fA-F]{1,16})$"
167+ )
168+
169+ cookie = self .args .get ("cookie" )
170+ if cookie is None :
171+ return "0x0"
172+
173+ m = COOKIE_REGEX .match (cookie )
174+ if m is None :
175+ log_and_raise_error (
176+ E_PARSER , "'{}' is not a valid cookie" .format (cookie )
177+ )
178+
179+ # normalize output (0x01Ff2 => 0x1ff2)
180+ return "0x{}" .format (m .group (1 ).lower ())
181+
164182 def read (self , key , parse_fn , dests = None ):
165183 # parse_fn can return a single value or a tuple of values.
166184 # In this case we are expecting dests to match the expected
@@ -303,6 +321,7 @@ def build_rule_string(direction, ofport, args, uplink=False):
303321 rule_parts = {
304322 "priority" : ("priority" , "priority" ),
305323 "protocol" : (None , None ),
324+ "cookie" : ("cookie" , "cookie" ),
306325 "ofport" : ("in_port" , "in_port" ),
307326 "mac" : ("dl_src" , "dl_dst" ),
308327 "iprange" : ("nw_dst" , "nw_src" ),
@@ -318,6 +337,7 @@ def build_rule_string(direction, ofport, args, uplink=False):
318337 if args .get ("priority" ):
319338 rule += "priority={}" .format (args ["priority" ]) + ","
320339 rule += args ["protocol" ]
340+ rule += ",cookie={}" .format (args ["cookie" ])
321341 if uplink :
322342 rule += ",dl_vlan={}" .format (vlanid )
323343 if ofport :
@@ -342,6 +362,7 @@ def run_ofctl_cmd(cmd, bridge, rule):
342362 % (format (ofctl_cmd ), cmd ["stderr" ]),
343363 )
344364 _LOGGER .info ("Applied rule: {}" .format (ofctl_cmd ))
365+ return cmd ["stdout" ]
345366
346367
347368@error_wrapped
@@ -358,6 +379,7 @@ def add_rule(_session, args):
358379 parser .read ("port" , parser .parse_port )
359380 parser .read ("allow" , parser .parse_allow )
360381 parser .read ("priority" , parser .parse_priority )
382+ parser .read ("cookie" , parser .parse_cookie )
361383 except XenAPIPlugin .Failure as e :
362384 log_and_raise_error (
363385 E_PARSER , "add_rule: Failed to get parameters: {}" .format (e .params [1 ])
@@ -383,6 +405,14 @@ def add_rule(_session, args):
383405 E_PORTS , "No ports found for bridge: {}" .format (rule_args ["bridge" ])
384406 )
385407
408+ # cleanup the cookie (if already used) to 'upgrade' the rule
409+ if rule_args ["cookie" ] != "0x0" :
410+ run_ofctl_cmd (
411+ "del-flows" ,
412+ rule_args ["parent-bridge" ],
413+ "cookie={}/-1" .format (rule_args ["cookie" ]),
414+ )
415+
386416 # We can now build the open flow rule
387417 rules = build_rules_strings (rule_args )
388418 _LOGGER .info ("Built rules: {}" .format (rules ))
@@ -408,6 +438,7 @@ def del_rule(_session, args):
408438 parser .read ("protocol" , parser .parse_protocol )
409439 parser .read ("iprange" , parser .parse_iprange )
410440 parser .read ("port" , parser .parse_port )
441+ parser .read ("cookie" , parser .parse_cookie )
411442 except XenAPIPlugin .Failure as e :
412443 log_and_raise_error (
413444 E_PARSER , "del_rule: Failed to get parameters: {}" .format (e .params [1 ])
@@ -427,12 +458,22 @@ def del_rule(_session, args):
427458 E_PARAMS , "del_rule: No port provided, tcp and udp requires one"
428459 )
429460
461+ # to match on a cookie, need to specify a mask
462+ rule_args ["cookie" ] = "{}/-1" .format (rule_args ["cookie" ])
463+
430464 update_args_from_ovs (rule_args )
431465
432- # We can now build the open flow rule
433- rules = build_rules_strings ( rule_args )
434- _LOGGER . info ( "Built rules: {}" . format ( rules ) )
466+ if rule_args [ "cookie" ] == "0x0/-1" :
467+ # if no cookie, build the open flow rule
468+ rules = build_rules_strings ( rule_args )
435469
470+ else :
471+ # if cookie value is meaningful, use it to remove all related rules
472+ rules = [
473+ "cookie={}" .format (rule_args ["cookie" ]),
474+ ]
475+
476+ _LOGGER .info ("Built rules: {}" .format (rules ))
436477 for rule in rules :
437478 run_ofctl_cmd ("del-flows" , rule_args ["parent-bridge" ], rule )
438479
0 commit comments