@@ -322,6 +322,22 @@ def _add_updatable_args(parser):
322322 action = 'store_true' ,
323323 help = _ ("NUMA affinity policy using legacy mode to schedule this port" ),
324324 )
325+ parser .add_argument (
326+ '--hint' ,
327+ metavar = '<alias=value>' ,
328+ action = JSONKeyValueAction ,
329+ default = {},
330+ help = _ (
331+ 'Port hints as ALIAS=VALUE or as JSON. '
332+ 'Valid hint aliases/values: '
333+ 'ovs-tx-steering=thread, ovs-tx-steering=hash. '
334+ 'Valid JSON values are as specified by the Neutron API. '
335+ '(requires port-hints extension) '
336+ '(requires port-hint-ovs-tx-steering extension for alias: '
337+ 'ovs-tx-steering) '
338+ '(repeat option to set multiple hints)'
339+ ),
340+ )
325341
326342
327343# TODO(abhiraut): Use the SDK resource mapped attribute names once the
@@ -350,6 +366,34 @@ def _convert_extra_dhcp_options(parsed_args):
350366 return dhcp_options
351367
352368
369+ # When we have multiple hints, we'll need to refactor this to allow
370+ # arbitrary combinations. But until then let's have it as simple as possible.
371+ def _validate_port_hints (hints ):
372+ if hints not in (
373+ {},
374+ # by hint alias
375+ {'ovs-tx-steering' : 'thread' },
376+ {'ovs-tx-steering' : 'hash' },
377+ # by fully specified value of the port's hints field
378+ {'openvswitch' : {'other_config' : {'tx-steering' : 'thread' }}},
379+ {'openvswitch' : {'other_config' : {'tx-steering' : 'hash' }}},
380+ ):
381+ msg = _ ("Invalid value to --hints, see --help for valid values." )
382+ raise argparse .ArgumentTypeError (msg )
383+
384+
385+ # When we have multiple hints, we'll need to refactor this to expand aliases
386+ # without losing other hints. But until then let's have it as simple as
387+ # possible.
388+ def _expand_port_hint_aliases (hints ):
389+ if hints == {'ovs-tx-steering' : 'thread' }:
390+ return {'openvswitch' : {'other_config' : {'tx-steering' : 'thread' }}}
391+ elif hints == {'ovs-tx-steering' : 'hash' }:
392+ return {'openvswitch' : {'other_config' : {'tx-steering' : 'hash' }}}
393+ else :
394+ return hints
395+
396+
353397class CreatePort (command .ShowOne , common .NeutronCommandWithExtraArgs ):
354398 _description = _ ("Create a new port" )
355399
@@ -527,6 +571,29 @@ def take_action(self, parsed_args):
527571 parsed_args .qos_policy , ignore_missing = False
528572 ).id
529573
574+ if parsed_args .hint :
575+ _validate_port_hints (parsed_args .hint )
576+ expanded_hints = _expand_port_hint_aliases (parsed_args .hint )
577+ try :
578+ client .find_extension ('port-hints' , ignore_missing = False )
579+ except Exception as e :
580+ msg = _ ('Not supported by Network API: %(e)s' ) % {'e' : e }
581+ raise exceptions .CommandError (msg )
582+ if (
583+ 'openvswitch' in expanded_hints
584+ and 'other_config' in expanded_hints ['openvswitch' ]
585+ and 'tx-steering'
586+ in expanded_hints ['openvswitch' ]['other_config' ]
587+ ):
588+ try :
589+ client .find_extension (
590+ 'port-hint-ovs-tx-steering' , ignore_missing = False
591+ )
592+ except Exception as e :
593+ msg = _ ('Not supported by Network API: %(e)s' ) % {'e' : e }
594+ raise exceptions .CommandError (msg )
595+ attrs ['hints' ] = expanded_hints
596+
530597 set_tags_in_post = bool (
531598 client .find_extension ('tag-ports-during-bulk-creation' )
532599 )
@@ -972,6 +1039,29 @@ def take_action(self, parsed_args):
9721039 if parsed_args .data_plane_status :
9731040 attrs ['data_plane_status' ] = parsed_args .data_plane_status
9741041
1042+ if parsed_args .hint :
1043+ _validate_port_hints (parsed_args .hint )
1044+ expanded_hints = _expand_port_hint_aliases (parsed_args .hint )
1045+ try :
1046+ client .find_extension ('port-hints' , ignore_missing = False )
1047+ except Exception as e :
1048+ msg = _ ('Not supported by Network API: %(e)s' ) % {'e' : e }
1049+ raise exceptions .CommandError (msg )
1050+ if (
1051+ 'openvswitch' in expanded_hints
1052+ and 'other_config' in expanded_hints ['openvswitch' ]
1053+ and 'tx-steering'
1054+ in expanded_hints ['openvswitch' ]['other_config' ]
1055+ ):
1056+ try :
1057+ client .find_extension (
1058+ 'port-hint-ovs-tx-steering' , ignore_missing = False
1059+ )
1060+ except Exception as e :
1061+ msg = _ ('Not supported by Network API: %(e)s' ) % {'e' : e }
1062+ raise exceptions .CommandError (msg )
1063+ attrs ['hints' ] = expanded_hints
1064+
9751065 attrs .update (
9761066 self ._parse_extra_properties (parsed_args .extra_properties )
9771067 )
@@ -1083,6 +1173,12 @@ def get_parser(self, prog_name):
10831173 default = False ,
10841174 help = _ ("Clear host binding for the port." ),
10851175 )
1176+ parser .add_argument (
1177+ '--hints' ,
1178+ action = 'store_true' ,
1179+ default = False ,
1180+ help = _ ("Clear hints for the port." ),
1181+ )
10861182
10871183 _tag .add_tag_option_to_parser_for_unset (parser , _ ('port' ))
10881184
@@ -1143,6 +1239,8 @@ def take_action(self, parsed_args):
11431239 attrs ['numa_affinity_policy' ] = None
11441240 if parsed_args .host :
11451241 attrs ['binding:host_id' ] = None
1242+ if parsed_args .hints :
1243+ attrs ['hints' ] = None
11461244
11471245 attrs .update (
11481246 self ._parse_extra_properties (parsed_args .extra_properties )
0 commit comments