Adding support for OVS Hybrid binding

Allows the OVS binding script to recognize if it
has to do hybrid binding or not and operate accordingly.

Closes-Bug: #1535828
Change-Id: I7c7d7b115b546c136a07880bc568662558dbc950
This commit is contained in:
Mohammad Banikazemi 2016-04-14 23:44:08 -04:00
parent b822c22c8f
commit cc05a7b903
4 changed files with 88 additions and 20 deletions

View File

@ -19,9 +19,11 @@ import pyroute2
from kuryr.common import config from kuryr.common import config
from kuryr.common import exceptions from kuryr.common import exceptions
from kuryr import utils
CONTAINER_VETH_POSTFIX = '_c' VETH_PREFIX = 'tap'
CONTAINER_VETH_PREFIX = 't_c'
BINDING_SUBCOMMAND = 'bind' BINDING_SUBCOMMAND = 'bind'
DOWN = 'DOWN' DOWN = 'DOWN'
FALLBACK_VIF_TYPE = 'unbound' FALLBACK_VIF_TYPE = 'unbound'
@ -32,8 +34,8 @@ KIND_VETH = 'veth'
MAC_ADDRESS_KEY = 'mac_address' MAC_ADDRESS_KEY = 'mac_address'
SUBNET_ID_KEY = 'subnet_id' SUBNET_ID_KEY = 'subnet_id'
UNBINDING_SUBCOMMAND = 'unbind' UNBINDING_SUBCOMMAND = 'unbind'
VETH_POSTFIX = '-veth'
VIF_TYPE_KEY = 'binding:vif_type' VIF_TYPE_KEY = 'binding:vif_type'
VIF_DETAILS_KEY = 'binding:vif_details'
_IPDB_CACHE = None _IPDB_CACHE = None
_IPROUTE_CACHE = None _IPROUTE_CACHE = None
@ -113,8 +115,8 @@ def port_bind(endpoint_id, neutron_port, neutron_subnets):
""" """
ip = get_ipdb() ip = get_ipdb()
ifname = endpoint_id[:8] + VETH_POSTFIX ifname = VETH_PREFIX + endpoint_id[:8]
peer_name = ifname + CONTAINER_VETH_POSTFIX peer_name = CONTAINER_VETH_PREFIX + ifname
subnets_dict = {subnet['id']: subnet for subnet in neutron_subnets} subnets_dict = {subnet['id']: subnet for subnet in neutron_subnets}
try: try:
@ -143,6 +145,7 @@ def port_bind(endpoint_id, neutron_port, neutron_subnets):
'Could not configure the veth endpoint for the container.') 'Could not configure the veth endpoint for the container.')
vif_type = neutron_port.get(VIF_TYPE_KEY, FALLBACK_VIF_TYPE) vif_type = neutron_port.get(VIF_TYPE_KEY, FALLBACK_VIF_TYPE)
vif_details = utils.string_mappings(neutron_port.get(VIF_DETAILS_KEY))
binding_exec_path = os.path.join(config.CONF.bindir, vif_type) binding_exec_path = os.path.join(config.CONF.bindir, vif_type)
port_id = neutron_port['id'] port_id = neutron_port['id']
network_id = neutron_port['network_id'] network_id = neutron_port['network_id']
@ -151,7 +154,7 @@ def port_bind(endpoint_id, neutron_port, neutron_subnets):
try: try:
stdout, stderr = processutils.execute( stdout, stderr = processutils.execute(
binding_exec_path, BINDING_SUBCOMMAND, port_id, ifname, binding_exec_path, BINDING_SUBCOMMAND, port_id, ifname,
endpoint_id, mac_address, network_id, tenant_id, endpoint_id, mac_address, network_id, tenant_id, vif_details,
run_as_root=True) run_as_root=True)
except processutils.ProcessExecutionError: except processutils.ProcessExecutionError:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
@ -171,13 +174,14 @@ def port_unbind(endpoint_id, neutron_port):
""" """
vif_type = neutron_port.get(VIF_TYPE_KEY, FALLBACK_VIF_TYPE) vif_type = neutron_port.get(VIF_TYPE_KEY, FALLBACK_VIF_TYPE)
vif_details = utils.string_mappings(neutron_port.get(VIF_DETAILS_KEY))
unbinding_exec_path = os.path.join(config.CONF.bindir, vif_type) unbinding_exec_path = os.path.join(config.CONF.bindir, vif_type)
ifname = endpoint_id[:8] + VETH_POSTFIX ifname = VETH_PREFIX + endpoint_id[:8]
port_id = neutron_port['id'] port_id = neutron_port['id']
mac_address = neutron_port['mac_address'] mac_address = neutron_port['mac_address']
stdout, stderr = processutils.execute( stdout, stderr = processutils.execute(
unbinding_exec_path, UNBINDING_SUBCOMMAND, port_id, ifname, unbinding_exec_path, UNBINDING_SUBCOMMAND, port_id, ifname,
endpoint_id, mac_address, run_as_root=True) endpoint_id, mac_address, vif_details, run_as_root=True)
try: try:
cleanup_veth(ifname) cleanup_veth(ifname)
except pyroute2.netlink.NetlinkError: except pyroute2.netlink.NetlinkError:

View File

@ -47,7 +47,7 @@ class TestKuryrJoinFailures(base.TestKuryrFailures):
fake_ifname = 'fake-veth' fake_ifname = 'fake-veth'
fake_binding_response = ( fake_binding_response = (
fake_ifname, fake_ifname,
fake_ifname + binding.CONTAINER_VETH_POSTFIX, binding.CONTAINER_VETH_PREFIX + fake_ifname,
('fake stdout', '') ('fake stdout', '')
) )
self.mox.StubOutWithMock(binding, 'port_bind') self.mox.StubOutWithMock(binding, 'port_bind')

View File

@ -167,3 +167,11 @@ def make_net_name(netid, tags=True):
if tags: if tags:
return const.NET_NAME_PREFIX + netid[:8] return const.NET_NAME_PREFIX + netid[:8]
return netid return netid
def string_mappings(mapping_list):
"""Make a string out of the mapping list"""
details = ''
if mapping_list:
details = '"' + str(mapping_list) + '"'
return details

View File

@ -12,42 +12,98 @@
# under the License. # under the License.
INT_BRIDGE="br-int" INT_BRIDGE="br-int"
HYBRID_PLUG="'ovs_hybrid_plug': True"
OPERATION=$1 OPERATION=$1
PORT=$2 PORT=$2
VETH=$3 VETH=$3
CONTAINER_UUID=$4 CONTAINER_UUID=$4
MAC_ADDRESS=$5 MAC_ADDRESS=$5
ovs_bind_port() {
bind_port() {
echo "plugging veth $VETH (Neutron port $PORT)..." echo "plugging veth $VETH (Neutron port $PORT)..."
sudo ovs-vsctl -- --may-exist add-port $INT_BRIDGE $VETH -- \ ovs-vsctl -- --may-exist add-port $INT_BRIDGE $VETH -- \
set interface $VETH external_ids:attached-mac=$MAC_ADDRESS \ set interface $VETH external_ids:attached-mac=$MAC_ADDRESS \
external_ids:iface-id=$PORT external_ids:vm-uuid=$CONTAINER_UUID \ external_ids:iface-id=$PORT external_ids:vm-uuid=$CONTAINER_UUID \
external_ids:iface-status=active external_ids:owner=kuryr external_ids:iface-status=active external_ids:owner=kuryr
} }
unbind_port() { ovs_unbind_port() {
echo "unplugging veth $PORT..." echo "unplugging port $PORT..."
PORT=`sudo ovs-vsctl --data=bare --no-heading --columns=name \ MYPORT=`ovs-vsctl --data=bare --no-heading --columns=name \
find interface external_ids:iface-id=$PORT \ find interface external_ids:iface-id=$PORT \
external_ids:owner=kuryr` external_ids:owner=kuryr`
if [ -z "$PORT" ]; then if [ -z "$MYPORT" ]; then
echo >&2 "Failed to find port $PORT." echo >&2 "Failed to find port $PORT."
exit 1 exit 1
fi fi
sudo ovs-vsctl del-port $INT_BRIDGE $PORT ovs-vsctl del-port $INT_BRIDGE $MYPORT
} }
ovs_hybrid_bind_port() {
echo "... plugging veth $VETH (Neutron port $PORT) ..."
# create a linux bridge
br_name="qbr"${PORT:0:11}
ip link add name $br_name type bridge
echo 0 > /sys/devices/virtual/net/$br_name/bridge/forward_delay
echo 0 > /sys/devices/virtual/net/$br_name/bridge/stp_state
# connect the veth outside to linux bridge
ip link set $VETH up
ip link set dev $VETH master $br_name
# create a veth pair to connect linux bridge and the integration bridge
veth_lb="qvb"${PORT:0:11}
veth_ovs="qvo"${PORT:0:11}
ip link add $veth_lb type veth peer name $veth_ovs
# connect one end to the linux bridge
ip link set dev $veth_lb master $br_name
ip link set $br_name up
# connect one end to the ovs integration bridge
ovs-vsctl add-port $INT_BRIDGE $veth_ovs -- \
set interface $veth_ovs external_ids:attached-mac=$MAC_ADDRESS \
external_ids:iface-id=$PORT external_ids:vm-id=$CONTAINER_UUID \
external_ids:iface-status=active external_ids:owner=kuryr
ip link set $veth_lb up
ip link set $veth_ovs up
}
ovs_hybrid_unbind_port() {
echo "unplugging port $PORT ..."
br_name="qbr"${PORT:0:11}
veth_lb="qvb"${PORT:0:11}
veth_ovs="qvo"${PORT:0:11}
ip link set dev $veth_lb nomaster
ovs-vsctl del-port $veth_ovs
ip link delete $veth_lb type veth
ip link set $br_name down
ip link delete $br_name type bridge
}
case $OPERATION in case $OPERATION in
"bind") "bind")
shift shift
bind_port if [ "${7/$HYBRID_PLUG}" = "$7" ]
then
ovs_bind_port
else
ovs_hybrid_bind_port
fi
exit 0 exit 0
;; ;;
"unbind") "unbind")
shift shift
unbind_port if [ "${5/$HYBRID_PLUG}" = "$5" ]
then
ovs_unbind_port
else
ovs_hybrid_unbind_port
fi
exit 0 exit 0
;; ;;
*) *)