Browse code

Merge "Add IPv6 support for tenant data network"

Jenkins authored on 2014/11/21 05:09:43
Showing 2 changed files
... ...
@@ -365,6 +365,35 @@ API rate limits
365 365
 
366 366
         API_RATE_LIMIT=False
367 367
 
368
+IP Version
369
+    | Default: ``IP_VERSION=4``
370
+    | This setting can be used to configure DevStack to create either an IPv4,
371
+      IPv6, or dual stack tenant data network by setting ``IP_VERSION`` to
372
+      either ``IP_VERSION=4``, ``IP_VERSION=6``, or ``IP_VERSION=4+6``
373
+      respectively. This functionality requires that the Neutron networking
374
+      service is enabled by setting the following options:
375
+    |
376
+
377
+    ::
378
+
379
+        disable_service n-net
380
+        enable_service q-svc q-agt q-dhcp q-l3
381
+
382
+    | The following optional variables can be used to alter the default IPv6
383
+      behavior:
384
+    |
385
+
386
+    ::
387
+
388
+        IPV6_RA_MODE=slaac
389
+        IPV6_ADDRESS_MODE=slaac
390
+        FIXED_RANGE_V6=fd$IPV6_GLOBAL_ID::/64
391
+        IPV6_PRIVATE_NETWORK_GATEWAY=fd$IPV6_GLOBAL_ID::1
392
+
393
+    | *Note: ``FIXED_RANGE_V6`` and ``IPV6_PRIVATE_NETWORK_GATEWAY``
394
+      can be configured with any valid IPv6 prefix. The default values make
395
+      use of an auto-generated ``IPV6_GLOBAL_ID`` to comply with RFC 4193.*
396
+
368 397
 Examples
369 398
 ========
370 399
 
... ...
@@ -51,10 +51,22 @@
51 51
 #
52 52
 # With Neutron networking the NETWORK_MANAGER variable is ignored.
53 53
 
54
+# Settings
55
+# --------
56
+
57
+# Timeout value in seconds to wait for IPv6 gateway configuration
58
+GATEWAY_TIMEOUT=30
59
+
54 60
 
55 61
 # Neutron Network Configuration
56 62
 # -----------------------------
57 63
 
64
+# Subnet IP version
65
+IP_VERSION=${IP_VERSION:-4}
66
+# Validate IP_VERSION
67
+if [[ $IP_VERSION != "4" ]] && [[ $IP_VERSION != "6" ]] && [[ $IP_VERSION != "4+6" ]]; then
68
+    die $LINENO "IP_VERSION must be either 4, 6, or 4+6"
69
+fi
58 70
 # Gateway and subnet defaults, in case they are not customized in localrc
59 71
 NETWORK_GATEWAY=${NETWORK_GATEWAY:-10.0.0.1}
60 72
 PUBLIC_NETWORK_GATEWAY=${PUBLIC_NETWORK_GATEWAY:-172.24.4.1}
... ...
@@ -65,6 +77,22 @@ if is_ssl_enabled_service "neutron" || is_service_enabled tls-proxy; then
65 65
     Q_PROTOCOL="https"
66 66
 fi
67 67
 
68
+# Generate 40-bit IPv6 Global ID to comply with RFC 4193
69
+IPV6_GLOBAL_ID=`uuidgen | sed s/-//g | cut -c 23- | sed -e "s/\(..\)\(....\)\(....\)/\1:\2:\3/"`
70
+
71
+# IPv6 gateway and subnet defaults, in case they are not customized in localrc
72
+IPV6_RA_MODE=${IPV6_RA_MODE:-slaac}
73
+IPV6_ADDRESS_MODE=${IPV6_ADDRESS_MODE:-slaac}
74
+IPV6_PUBLIC_SUBNET_NAME=${IPV6_PUBLIC_SUBNET_NAME:-ipv6-public-subnet}
75
+IPV6_PRIVATE_SUBNET_NAME=${IPV6_PRIVATE_SUBNET_NAME:-ipv6-private-subnet}
76
+FIXED_RANGE_V6=${FIXED_RANGE_V6:-fd$IPV6_GLOBAL_ID::/64}
77
+IPV6_PRIVATE_NETWORK_GATEWAY=${IPV6_PRIVATE_NETWORK_GATEWAY:-fd$IPV6_GLOBAL_ID::1}
78
+IPV6_PUBLIC_RANGE=${IPV6_PUBLIC_RANGE:-fe80:cafe:cafe::/64}
79
+IPV6_PUBLIC_NETWORK_GATEWAY=${IPV6_PUBLIC_NETWORK_GATEWAY:-fe80:cafe:cafe::2}
80
+# IPV6_ROUTER_GW_IP must be defined when IP_VERSION=4+6 as it cannot be
81
+# obtained conventionally until the l3-agent has support for dual-stack
82
+# TODO (john-davidge) Remove once l3-agent supports dual-stack
83
+IPV6_ROUTER_GW_IP=${IPV6_ROUTER_GW_IP:-fe80:cafe:cafe::1}
68 84
 
69 85
 # Set up default directories
70 86
 GITDIR["python-neutronclient"]=$DEST/python-neutronclient
... ...
@@ -531,8 +559,16 @@ function create_neutron_initial_network {
531 531
     else
532 532
         NET_ID=$(neutron net-create --tenant-id $TENANT_ID "$PRIVATE_NETWORK_NAME" | grep ' id ' | get_field 2)
533 533
         die_if_not_set $LINENO NET_ID "Failure creating NET_ID for $PHYSICAL_NETWORK $TENANT_ID"
534
-        SUBNET_ID=$(neutron subnet-create --tenant-id $TENANT_ID --ip_version 4 --gateway $NETWORK_GATEWAY --name $PRIVATE_SUBNET_NAME $NET_ID $FIXED_RANGE | grep ' id ' | get_field 2)
535
-        die_if_not_set $LINENO SUBNET_ID "Failure creating SUBNET_ID for $TENANT_ID"
534
+
535
+        if [[ "$IP_VERSION" =~ 4.* ]]; then
536
+            # Create IPv4 private subnet
537
+            SUBNET_ID=$(_neutron_create_private_subnet_v4)
538
+        fi
539
+
540
+        if [[ "$IP_VERSION" =~ .*6 ]]; then
541
+            # Create IPv6 private subnet
542
+            IPV6_SUBNET_ID=$(_neutron_create_private_subnet_v6)
543
+        fi
536 544
     fi
537 545
 
538 546
     if [[ "$Q_L3_ENABLED" == "True" ]]; then
... ...
@@ -546,7 +582,7 @@ function create_neutron_initial_network {
546 546
             ROUTER_ID=$(neutron router-create $Q_ROUTER_NAME | grep ' id ' | get_field 2)
547 547
             die_if_not_set $LINENO ROUTER_ID "Failure creating ROUTER_ID for $Q_ROUTER_NAME"
548 548
         fi
549
-        neutron router-interface-add $ROUTER_ID $SUBNET_ID
549
+
550 550
         # Create an external network, and a subnet. Configure the external network as router gw
551 551
         if [ "$Q_USE_PROVIDERNET_FOR_PUBLIC" = "True" ]; then
552 552
             EXT_NET_ID=$(neutron net-create "$PUBLIC_NETWORK_NAME" -- --router:external=True --provider:network_type=flat --provider:physical_network=${PUBLIC_PHYSICAL_NETWORK} | grep ' id ' | get_field 2)
... ...
@@ -554,35 +590,15 @@ function create_neutron_initial_network {
554 554
             EXT_NET_ID=$(neutron net-create "$PUBLIC_NETWORK_NAME" -- --router:external=True | grep ' id ' | get_field 2)
555 555
         fi
556 556
         die_if_not_set $LINENO EXT_NET_ID "Failure creating EXT_NET_ID for $PUBLIC_NETWORK_NAME"
557
-        EXT_GW_IP=$(neutron subnet-create --ip_version 4 ${Q_FLOATING_ALLOCATION_POOL:+--allocation-pool $Q_FLOATING_ALLOCATION_POOL} --gateway $PUBLIC_NETWORK_GATEWAY --name $PUBLIC_SUBNET_NAME $EXT_NET_ID $FLOATING_RANGE -- --enable_dhcp=False | grep 'gateway_ip' | get_field 2)
558
-        die_if_not_set $LINENO EXT_GW_IP "Failure creating EXT_GW_IP"
559
-        neutron router-gateway-set $ROUTER_ID $EXT_NET_ID
560 557
 
561
-        if is_service_enabled q-l3; then
562
-            # logic is specific to using the l3-agent for l3
563
-            if is_neutron_ovs_base_plugin && [[ "$Q_USE_NAMESPACE" = "True" ]]; then
564
-                local ext_gw_interface
565
-
566
-                if [[ "$Q_USE_PUBLIC_VETH" = "True" ]]; then
567
-                    ext_gw_interface=$Q_PUBLIC_VETH_EX
568
-                else
569
-                    # Disable in-band as we are going to use local port
570
-                    # to communicate with VMs
571
-                    sudo ovs-vsctl set Bridge $PUBLIC_BRIDGE \
572
-                        other_config:disable-in-band=true
573
-                    ext_gw_interface=$PUBLIC_BRIDGE
574
-                fi
575
-                CIDR_LEN=${FLOATING_RANGE#*/}
576
-                sudo ip addr add $EXT_GW_IP/$CIDR_LEN dev $ext_gw_interface
577
-                sudo ip link set $ext_gw_interface up
578
-                ROUTER_GW_IP=`neutron port-list -c fixed_ips -c device_owner | grep router_gateway | awk -F '"' '{ print $8; }'`
579
-                die_if_not_set $LINENO ROUTER_GW_IP "Failure retrieving ROUTER_GW_IP"
580
-                sudo route add -net $FIXED_RANGE gw $ROUTER_GW_IP
581
-            fi
582
-            if [[ "$Q_USE_NAMESPACE" == "False" ]]; then
583
-                # Explicitly set router id in l3 agent configuration
584
-                iniset $Q_L3_CONF_FILE DEFAULT router_id $ROUTER_ID
585
-            fi
558
+        if [[ "$IP_VERSION" =~ 4.* ]]; then
559
+            # Configure router for IPv4 public access
560
+            _neutron_configure_router_v4
561
+        fi
562
+
563
+        if [[ "$IP_VERSION" =~ .*6 ]]; then
564
+            # Configure router for IPv6 public access
565
+            _neutron_configure_router_v6
586 566
         fi
587 567
     fi
588 568
 }
... ...
@@ -1065,6 +1081,172 @@ function _neutron_setup_interface_driver {
1065 1065
     neutron_plugin_setup_interface_driver $1
1066 1066
 }
1067 1067
 
1068
+# Create private IPv4 subnet
1069
+function _neutron_create_private_subnet_v4 {
1070
+    local subnet_params="--tenant-id $TENANT_ID "
1071
+    subnet_params+="--ip_version 4 "
1072
+    subnet_params+="--gateway $NETWORK_GATEWAY "
1073
+    subnet_params+="--name $PRIVATE_SUBNET_NAME "
1074
+    subnet_params+="$NET_ID $FIXED_RANGE"
1075
+    local subnet_id=$(neutron subnet-create $subnet_params | grep ' id ' | get_field 2)
1076
+    die_if_not_set $LINENO subnet_id "Failure creating private IPv4 subnet for $TENANT_ID"
1077
+    echo $subnet_id
1078
+}
1079
+
1080
+# Create private IPv6 subnet
1081
+function _neutron_create_private_subnet_v6 {
1082
+    die_if_not_set $LINENO IPV6_RA_MODE "IPV6 RA Mode not set"
1083
+    die_if_not_set $LINENO IPV6_ADDRESS_MODE "IPV6 Address Mode not set"
1084
+    local ipv6_modes="--ipv6-ra-mode $IPV6_RA_MODE --ipv6-address-mode $IPV6_ADDRESS_MODE"
1085
+    local subnet_params="--tenant-id $TENANT_ID "
1086
+    subnet_params+="--ip_version 6 "
1087
+    subnet_params+="--gateway $IPV6_PRIVATE_NETWORK_GATEWAY "
1088
+    subnet_params+="--name $IPV6_PRIVATE_SUBNET_NAME "
1089
+    subnet_params+="$NET_ID $FIXED_RANGE_V6 $ipv6_modes"
1090
+    local ipv6_subnet_id=$(neutron subnet-create $subnet_params | grep ' id ' | get_field 2)
1091
+    die_if_not_set $LINENO ipv6_subnet_id "Failure creating private IPv6 subnet for $TENANT_ID"
1092
+    echo $ipv6_subnet_id
1093
+}
1094
+
1095
+# Create public IPv4 subnet
1096
+function _neutron_create_public_subnet_v4 {
1097
+    local subnet_params+="--ip_version 4 "
1098
+    subnet_params+="${Q_FLOATING_ALLOCATION_POOL:+--allocation-pool $Q_FLOATING_ALLOCATION_POOL} "
1099
+    subnet_params+="--gateway $PUBLIC_NETWORK_GATEWAY "
1100
+    subnet_params+="--name $PUBLIC_SUBNET_NAME "
1101
+    subnet_params+="$EXT_NET_ID $FLOATING_RANGE "
1102
+    subnet_params+="-- --enable_dhcp=False"
1103
+    local id_and_ext_gw_ip=$(neutron subnet-create $subnet_params | grep -e 'gateway_ip' -e ' id ')
1104
+    die_if_not_set $LINENO id_and_ext_gw_ip "Failure creating public IPv4 subnet"
1105
+    echo $id_and_ext_gw_ip
1106
+}
1107
+
1108
+# Create public IPv6 subnet
1109
+function _neutron_create_public_subnet_v6 {
1110
+    local subnet_params="--ip_version 6 "
1111
+    subnet_params+="--gateway $IPV6_PUBLIC_NETWORK_GATEWAY "
1112
+    subnet_params+="--name $IPV6_PUBLIC_SUBNET_NAME "
1113
+    subnet_params+="$EXT_NET_ID $IPV6_PUBLIC_RANGE "
1114
+    subnet_params+="-- --enable_dhcp=False"
1115
+    local ipv6_id_and_ext_gw_ip=$(neutron subnet-create $subnet_params | grep -e 'gateway_ip' -e ' id ')
1116
+    die_if_not_set $LINENO ipv6_id_and_ext_gw_ip "Failure creating an IPv6 public subnet"
1117
+    echo $ipv6_id_and_ext_gw_ip
1118
+}
1119
+
1120
+# Configure neutron router for IPv4 public access
1121
+function _neutron_configure_router_v4 {
1122
+    neutron router-interface-add $ROUTER_ID $SUBNET_ID
1123
+    # Create a public subnet on the external network
1124
+    local id_and_ext_gw_ip=$(_neutron_create_public_subnet_v4 $EXT_NET_ID)
1125
+    local ext_gw_ip=$(echo $id_and_ext_gw_ip  | get_field 2)
1126
+    PUB_SUBNET_ID=$(echo $id_and_ext_gw_ip | get_field 5)
1127
+    # Configure the external network as the default router gateway
1128
+    neutron router-gateway-set $ROUTER_ID $EXT_NET_ID
1129
+
1130
+    # This logic is specific to using the l3-agent for layer 3
1131
+    if is_service_enabled q-l3; then
1132
+        # Configure and enable public bridge
1133
+        if is_neutron_ovs_base_plugin && [[ "$Q_USE_NAMESPACE" = "True" ]]; then
1134
+            local ext_gw_interface=$(_neutron_get_ext_gw_interface)
1135
+            local cidr_len=${FLOATING_RANGE#*/}
1136
+            sudo ip addr add $ext_gw_ip/$cidr_len dev $ext_gw_interface
1137
+            sudo ip link set $ext_gw_interface up
1138
+            ROUTER_GW_IP=`neutron port-list -c fixed_ips -c device_owner | grep router_gateway | awk -F '"' -v subnet_id=$PUB_SUBNET_ID '$4 == subnet_id { print $8; }'`
1139
+            die_if_not_set $LINENO ROUTER_GW_IP "Failure retrieving ROUTER_GW_IP"
1140
+            sudo route add -net $FIXED_RANGE gw $ROUTER_GW_IP
1141
+        fi
1142
+        _neutron_set_router_id
1143
+    fi
1144
+}
1145
+
1146
+# Configure neutron router for IPv6 public access
1147
+function _neutron_configure_router_v6 {
1148
+    neutron router-interface-add $ROUTER_ID $IPV6_SUBNET_ID
1149
+    # Create a public subnet on the external network
1150
+    local ipv6_id_and_ext_gw_ip=$(_neutron_create_public_subnet_v6 $EXT_NET_ID)
1151
+    local ipv6_ext_gw_ip=$(echo $ipv6_id_and_ext_gw_ip | get_field 2)
1152
+    local ipv6_pub_subnet_id=$(echo $ipv6_id_and_ext_gw_ip | get_field 5)
1153
+
1154
+    # If the external network has not already been set as the default router
1155
+    # gateway when configuring an IPv4 public subnet, do so now
1156
+    if [[ "$IP_VERSION" == "6" ]]; then
1157
+        neutron router-gateway-set $ROUTER_ID $EXT_NET_ID
1158
+    fi
1159
+
1160
+    # This logic is specific to using the l3-agent for layer 3
1161
+    if is_service_enabled q-l3; then
1162
+        local ipv6_router_gw_port
1163
+        # Ensure IPv6 forwarding is enabled on the host
1164
+        sudo sysctl -w net.ipv6.conf.all.forwarding=1
1165
+        # Configure and enable public bridge
1166
+        if [[ "$IP_VERSION" = "6" ]]; then
1167
+            # Override global IPV6_ROUTER_GW_IP with the true value from neutron
1168
+            IPV6_ROUTER_GW_IP=`neutron port-list -c fixed_ips -c device_owner | grep router_gateway | awk -F '"' -v subnet_id=$ipv6_pub_subnet_id '$4 == subnet_id { print $8; }'`
1169
+            die_if_not_set $LINENO IPV6_ROUTER_GW_IP "Failure retrieving IPV6_ROUTER_GW_IP"
1170
+            ipv6_router_gw_port=`neutron port-list -c id -c fixed_ips -c device_owner | grep router_gateway | awk -F '"' -v subnet_id=$ipv6_pub_subnet_id '$4 == subnet_id { print $1; }' | awk -F ' | ' '{ print $2; }'`
1171
+            die_if_not_set $LINENO ipv6_router_gw_port "Failure retrieving ipv6_router_gw_port"
1172
+        else
1173
+            ipv6_router_gw_port=`neutron port-list -c id -c fixed_ips -c device_owner | grep router_gateway | awk -F '"' -v subnet_id=$PUB_SUBNET_ID '$4 == subnet_id { print $1; }' | awk -F ' | ' '{ print $2; }'`
1174
+            die_if_not_set $LINENO ipv6_router_gw_port "Failure retrieving ipv6_router_gw_port"
1175
+        fi
1176
+
1177
+        # The ovs_base_configure_l3_agent function flushes the public
1178
+        # bridge's ip addresses, so turn IPv6 support in the host off
1179
+        # and then on to recover the public bridge's link local address
1180
+        sudo sysctl -w net.ipv6.conf.${PUBLIC_BRIDGE}.disable_ipv6=1
1181
+        sudo sysctl -w net.ipv6.conf.${PUBLIC_BRIDGE}.disable_ipv6=0
1182
+        if is_neutron_ovs_base_plugin && [[ "$Q_USE_NAMESPACE" = "True" ]]; then
1183
+            local ext_gw_interface=$(_neutron_get_ext_gw_interface)
1184
+            local ipv6_cidr_len=${IPV6_PUBLIC_RANGE#*/}
1185
+
1186
+            # Define router_ns based on whether DVR is enabled
1187
+            local router_ns=qrouter
1188
+            if [[ "$Q_DVR_MODE" == "dvr_snat" ]]; then
1189
+                router_ns=snat
1190
+            fi
1191
+
1192
+            # Configure interface for public bridge
1193
+            sudo ip -6 addr add $ipv6_ext_gw_ip/$ipv6_cidr_len dev $ext_gw_interface
1194
+
1195
+            # Wait until layer 3 agent has configured the gateway port on
1196
+            # the public bridge, then add gateway address to the interface
1197
+            # TODO (john-davidge) Remove once l3-agent supports dual-stack
1198
+            if [[ "$IP_VERSION" == "4+6" ]]; then
1199
+                if ! timeout $GATEWAY_TIMEOUT sh -c "until sudo ip netns exec $router_ns-$ROUTER_ID ip addr show qg-${ipv6_router_gw_port:0:11} | grep $ROUTER_GW_IP; do sleep 1; done"; then
1200
+                    die $LINENO "Timeout retrieving ROUTER_GW_IP"
1201
+                fi
1202
+                # Configure the gateway port with the public IPv6 adress
1203
+                sudo ip netns exec $router_ns-$ROUTER_ID ip -6 addr add $IPV6_ROUTER_GW_IP/$ipv6_cidr_len dev qg-${ipv6_router_gw_port:0:11}
1204
+                # Add a default IPv6 route to the neutron router as the
1205
+                # l3-agent does not add one in the dual-stack case
1206
+                sudo ip netns exec $router_ns-$ROUTER_ID ip -6 route replace default via $ipv6_ext_gw_ip dev qg-${ipv6_router_gw_port:0:11}
1207
+            fi
1208
+            sudo ip -6 route add $FIXED_RANGE_V6 via $IPV6_ROUTER_GW_IP dev $ext_gw_interface
1209
+        fi
1210
+        _neutron_set_router_id
1211
+    fi
1212
+}
1213
+
1214
+# Explicitly set router id in l3 agent configuration
1215
+function _neutron_set_router_id {
1216
+    if [[ "$Q_USE_NAMESPACE" == "False" ]]; then
1217
+        iniset $Q_L3_CONF_FILE DEFAULT router_id $ROUTER_ID
1218
+    fi
1219
+}
1220
+
1221
+# Get ext_gw_interface depending on value of Q_USE_PUBLIC_VETH
1222
+function _neutron_get_ext_gw_interface {
1223
+    if [[ "$Q_USE_PUBLIC_VETH" == "True" ]]; then
1224
+        echo $Q_PUBLIC_VETH_EX
1225
+    else
1226
+        # Disable in-band as we are going to use local port
1227
+        # to communicate with VMs
1228
+        sudo ovs-vsctl set Bridge $PUBLIC_BRIDGE \
1229
+            other_config:disable-in-band=true
1230
+        echo $PUBLIC_BRIDGE
1231
+    fi
1232
+}
1233
+
1068 1234
 # Functions for Neutron Exercises
1069 1235
 #--------------------------------
1070 1236