Skip to content

Commit 969e6ab

Browse files
author
Brian Haley
committed
Support IPv6 addresses better
When adding a security group rule, if no IP address is given we will use '0.0.0.0/0', but if the ethertype is IPv6 we will leave it as None. Change this to be '::/0' to match what we do for IPv4 - use the "any" address. The neutron server treats them both the same when checking for duplicates. Because there are most likely entries in the DB using None for the IP, print them as '0.0.0.0/0' or '::/0' so it is more obvious what address they are actually referring to. Also change to display the Ethertype column by default instead of with --long, since easily knowing IPv4 or IPv6 is useful. Change-Id: Ic396fc23caa66b6b0034c5d30b27c6ed499de5a6 Closes-bug: #1735575
1 parent b41d751 commit 969e6ab

5 files changed

Lines changed: 79 additions & 15 deletions

File tree

doc/source/cli/command-objects/security-group-rule.rst

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ Create a new security group rule
2727
2828
.. option:: --remote-ip <ip-address>
2929
30-
Remote IP address block
31-
(may use CIDR notation; default for IPv4 rule: 0.0.0.0/0)
30+
Remote IP address block (may use CIDR notation;
31+
default for IPv4 rule: 0.0.0.0/0,
32+
default for IPv6 rule: ::/0)
3233
3334
.. option:: --remote-group <group>
3435
@@ -134,6 +135,7 @@ List security group rules
134135
openstack security group rule list
135136
[--all-projects]
136137
[--protocol <protocol>]
138+
[--ethertype <ethertype>]
137139
[--ingress | --egress]
138140
[--long]
139141
[<group>]
@@ -151,7 +153,6 @@ List security group rules
151153
152154
*Compute version 2 does not have additional fields to display.*
153155
154-
155156
.. option:: --protocol
156157
157158
List rules by the IP protocol (ah, dhcp, egp, esp, gre, icmp, igmp,
@@ -161,6 +162,12 @@ List security group rules
161162
162163
*Network version 2*
163164
165+
.. option:: --ethertype
166+
167+
List rules by the Ethertype (IPv4 or IPv6)
168+
169+
*Network version 2*
170+
164171
.. option:: --ingress
165172
166173
List rules applied to incoming network traffic

openstackclient/network/v2/security_group_rule.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ def _format_network_port_range(rule):
6262
return port_range
6363

6464

65+
def _format_remote_ip_prefix(rule):
66+
remote_ip_prefix = rule['remote_ip_prefix']
67+
if remote_ip_prefix is None:
68+
ethertype = rule['ether_type']
69+
if ethertype == 'IPv4':
70+
remote_ip_prefix = '0.0.0.0/0'
71+
elif ethertype == 'IPv6':
72+
remote_ip_prefix = '::/0'
73+
return remote_ip_prefix
74+
75+
6576
def _get_columns(item):
6677
column_map = {
6778
'tenant_id': 'project_id',
@@ -108,7 +119,8 @@ def update_parser_common(self, parser):
108119
"--remote-ip",
109120
metavar="<ip-address>",
110121
help=_("Remote IP address block (may use CIDR notation; "
111-
"default for IPv4 rule: 0.0.0.0/0)"),
122+
"default for IPv4 rule: 0.0.0.0/0, "
123+
"default for IPv6 rule: ::/0)"),
112124
)
113125
remote_group.add_argument(
114126
"--remote-group",
@@ -230,6 +242,14 @@ def _get_protocol(self, parsed_args, default_protocol='any'):
230242
protocol = None
231243
return protocol
232244

245+
def _get_ethertype(self, parsed_args, protocol):
246+
ethertype = 'IPv4'
247+
if parsed_args.ethertype is not None:
248+
ethertype = parsed_args.ethertype
249+
elif self._is_ipv6_protocol(protocol):
250+
ethertype = 'IPv6'
251+
return ethertype
252+
233253
def _is_ipv6_protocol(self, protocol):
234254
# NOTE(rtheis): Neutron has deprecated protocol icmpv6.
235255
# However, while the OSC CLI doesn't document the protocol,
@@ -264,12 +284,8 @@ def take_action_network(self, client, parsed_args):
264284

265285
# NOTE(rtheis): Use ethertype specified else default based
266286
# on IP protocol.
267-
if parsed_args.ethertype:
268-
attrs['ethertype'] = parsed_args.ethertype
269-
elif self._is_ipv6_protocol(attrs['protocol']):
270-
attrs['ethertype'] = 'IPv6'
271-
else:
272-
attrs['ethertype'] = 'IPv4'
287+
attrs['ethertype'] = self._get_ethertype(parsed_args,
288+
attrs['protocol'])
273289

274290
# NOTE(rtheis): Validate the port range and ICMP type and code.
275291
# It would be ideal if argparse could do this.
@@ -306,6 +322,8 @@ def take_action_network(self, client, parsed_args):
306322
attrs['remote_ip_prefix'] = parsed_args.remote_ip
307323
elif attrs['ethertype'] == 'IPv4':
308324
attrs['remote_ip_prefix'] = '0.0.0.0/0'
325+
elif attrs['ethertype'] == 'IPv6':
326+
attrs['remote_ip_prefix'] = '::/0'
309327
attrs['security_group_id'] = security_group_id
310328
if parsed_args.project is not None:
311329
identity_client = self.app.client_manager.identity
@@ -387,6 +405,7 @@ def _format_network_security_group_rule(self, rule):
387405
"""
388406
rule = rule.to_dict()
389407
rule['port_range'] = _format_network_port_range(rule)
408+
rule['remote_ip_prefix'] = _format_remote_ip_prefix(rule)
390409
return rule
391410

392411
def update_parser_common(self, parser):
@@ -418,6 +437,12 @@ def update_parser_network(self, parser):
418437
"udp, udplite, vrrp and integer representations [0-255] "
419438
"or any; default: any (all protocols))")
420439
)
440+
parser.add_argument(
441+
'--ethertype',
442+
metavar='<ethertype>',
443+
type=_convert_to_lowercase,
444+
help=_("List rules by the Ethertype (IPv4 or IPv6)")
445+
)
421446
direction_group = parser.add_mutually_exclusive_group()
422447
direction_group.add_argument(
423448
'--ingress',
@@ -458,11 +483,12 @@ def _get_column_headers(self, parsed_args):
458483
column_headers = (
459484
'ID',
460485
'IP Protocol',
486+
'Ethertype',
461487
'IP Range',
462488
'Port Range',
463489
)
464490
if parsed_args.long:
465-
column_headers = column_headers + ('Direction', 'Ethertype',)
491+
column_headers = column_headers + ('Direction',)
466492
column_headers = column_headers + ('Remote Security Group',)
467493
if parsed_args.group is None:
468494
column_headers = column_headers + ('Security Group',)
@@ -473,11 +499,12 @@ def take_action_network(self, client, parsed_args):
473499
columns = (
474500
'id',
475501
'protocol',
502+
'ether_type',
476503
'remote_ip_prefix',
477504
'port_range',
478505
)
479506
if parsed_args.long:
480-
columns = columns + ('direction', 'ether_type',)
507+
columns = columns + ('direction',)
481508
columns = columns + ('remote_group_id',)
482509

483510
# Get the security group rules using the requested query.
@@ -516,6 +543,7 @@ def take_action_compute(self, client, parsed_args):
516543
columns = (
517544
"ID",
518545
"IP Protocol",
546+
"Ethertype",
519547
"IP Range",
520548
"Port Range",
521549
"Remote Security Group",
@@ -564,6 +592,9 @@ def update_parser_common(self, parser):
564592
def take_action_network(self, client, parsed_args):
565593
obj = client.find_security_group_rule(parsed_args.rule,
566594
ignore_missing=False)
595+
# necessary for old rules that have None in this field
596+
if not obj['remote_ip_prefix']:
597+
obj['remote_ip_prefix'] = _format_remote_ip_prefix(obj)
567598
display_columns, columns = _get_columns(obj)
568599
data = utils.get_item_properties(obj, columns)
569600
return (display_columns, data)

openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,13 +337,15 @@ class TestListSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
337337
_security_group_rule_tcp = \
338338
compute_fakes.FakeSecurityGroupRule.create_one_security_group_rule({
339339
'ip_protocol': 'tcp',
340+
'ethertype': 'IPv4',
340341
'from_port': 80,
341342
'to_port': 80,
342343
'group': {'name': _security_group['name']},
343344
})
344345
_security_group_rule_icmp = \
345346
compute_fakes.FakeSecurityGroupRule.create_one_security_group_rule({
346347
'ip_protocol': 'icmp',
348+
'ethertype': 'IPv4',
347349
'from_port': -1,
348350
'to_port': -1,
349351
'ip_range': {'cidr': '10.0.2.0/24'},
@@ -357,6 +359,7 @@ class TestListSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
357359
expected_columns_with_group = (
358360
'ID',
359361
'IP Protocol',
362+
'Ethertype',
360363
'IP Range',
361364
'Port Range',
362365
'Remote Security Group',
@@ -373,6 +376,7 @@ class TestListSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
373376
expected_rule_with_group = (
374377
rule['id'],
375378
rule['ip_protocol'],
379+
rule['ethertype'],
376380
rule['ip_range'],
377381
rule['port_range'],
378382
rule['remote_security_group'],

openstackclient/tests/unit/network/v2/test_security_group_rule_network.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ def test_create_network_options(self):
388388
'port_range_min': 443,
389389
'protocol': '6',
390390
'remote_group_id': None,
391-
'remote_ip_prefix': None,
391+
'remote_ip_prefix': '::/0',
392392
})
393393
arglist = [
394394
'--dst-port', str(self._security_group_rule.port_range_min),
@@ -419,6 +419,7 @@ def test_create_network_options(self):
419419
'port_range_max': self._security_group_rule.port_range_max,
420420
'port_range_min': self._security_group_rule.port_range_min,
421421
'protocol': self._security_group_rule.protocol,
422+
'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
422423
'security_group_id': self._security_group.id,
423424
'tenant_id': self.project.id,
424425
})
@@ -664,6 +665,7 @@ def test_create_ipv6_icmp_type_code(self):
664665
'port_range_min': 139,
665666
'port_range_max': 2,
666667
'protocol': 'ipv6-icmp',
668+
'remote_ip_prefix': '::/0',
667669
})
668670
arglist = [
669671
'--icmp-type', str(self._security_group_rule.port_range_min),
@@ -688,6 +690,7 @@ def test_create_ipv6_icmp_type_code(self):
688690
'port_range_min': self._security_group_rule.port_range_min,
689691
'port_range_max': self._security_group_rule.port_range_max,
690692
'protocol': self._security_group_rule.protocol,
693+
'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
691694
'security_group_id': self._security_group.id,
692695
})
693696
self.assertEqual(self.expected_columns, columns)
@@ -698,6 +701,7 @@ def test_create_icmpv6_type(self):
698701
'ether_type': 'IPv6',
699702
'port_range_min': 139,
700703
'protocol': 'icmpv6',
704+
'remote_ip_prefix': '::/0',
701705
})
702706
arglist = [
703707
'--icmp-type', str(self._security_group_rule.port_range_min),
@@ -720,6 +724,7 @@ def test_create_icmpv6_type(self):
720724
'ethertype': self._security_group_rule.ether_type,
721725
'port_range_min': self._security_group_rule.port_range_min,
722726
'protocol': self._security_group_rule.protocol,
727+
'remote_ip_prefix': self._security_group_rule.remote_ip_prefix,
723728
'security_group_id': self._security_group.id,
724729
})
725730
self.assertEqual(self.expected_columns, columns)
@@ -868,15 +873,16 @@ class TestListSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
868873
expected_columns_with_group_and_long = (
869874
'ID',
870875
'IP Protocol',
876+
'Ethertype',
871877
'IP Range',
872878
'Port Range',
873879
'Direction',
874-
'Ethertype',
875880
'Remote Security Group',
876881
)
877882
expected_columns_no_group = (
878883
'ID',
879884
'IP Protocol',
885+
'Ethertype',
880886
'IP Range',
881887
'Port Range',
882888
'Remote Security Group',
@@ -889,16 +895,17 @@ class TestListSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
889895
expected_data_with_group_and_long.append((
890896
_security_group_rule.id,
891897
_security_group_rule.protocol,
898+
_security_group_rule.ether_type,
892899
_security_group_rule.remote_ip_prefix,
893900
security_group_rule._format_network_port_range(
894901
_security_group_rule),
895902
_security_group_rule.direction,
896-
_security_group_rule.ether_type,
897903
_security_group_rule.remote_group_id,
898904
))
899905
expected_data_no_group.append((
900906
_security_group_rule.id,
901907
_security_group_rule.protocol,
908+
_security_group_rule.ether_type,
902909
_security_group_rule.remote_ip_prefix,
903910
security_group_rule._format_network_port_range(
904911
_security_group_rule),
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
features:
3+
- |
4+
Security group rules can now be filtered by Ethertype in
5+
``security group rule list`` using ``--ethertype`` with either
6+
``ipv4`` or ``ipv6`` as an argument.
7+
upgrade:
8+
- |
9+
Security group rule listings now have the ``Ethertype`` field displayed
10+
by default to more easily differentiate between IPv4 and IPv6 rules.
11+
In addition, the ``IP Range`` field of a security group will be
12+
changed to ``0.0.0.0/0`` for IPv4 and ``::/0`` for IPv6 if no
13+
value is returned for the address, based on the Ethertype field of
14+
the rule. For further information see
15+
[Bug `1735575 <https://bugs.launchpad.net/bugs/1735575>`_]

0 commit comments

Comments
 (0)