Ejemplo n.º 1
0
    def _cleanup_evpn2ipvpn(self, ipvpn):
        (_, ipvpn_if, _, managed) = self._evpn_ipvpn_ifs[ipvpn]

        # cleanup veth pair
        if managed:
            runCommand(log, "ovs-vsctl del-port %s" % ipvpn_if)
            runCommand(log, "ip link delete %s" % ipvpn_if)
Ejemplo n.º 2
0
    def _cleanup_evpn2ipvpn(self, ipvpn):
        (_, ipvpn_if, _, managed) = self._evpn_ipvpn_ifs[ipvpn]

        # cleanup veth pair
        if managed:
            runCommand(log, "ovs-vsctl del-port %s" % ipvpn_if)
            runCommand(log, "ip link delete %s" % ipvpn_if)
Ejemplo n.º 3
0
def deleteNetNSlink(docker_container_pid):
    vpn2ns = get_vpn2ns_if_name(docker_container_pid)
    try:
        """ Remove a netns for running docker container """
        runCommand(log, "ip netns delete %s" % docker_container_pid)
        runCommand(log, "ip link delete %s" % vpn2ns)
    except:
        raise Exception("Can't remove netns %s doesn't exist"  % docker_container_pid)
Ejemplo n.º 4
0
def deleteNetNSlink(docker_container_pid):
    vpn2ns = get_vpn2ns_if_name(docker_container_pid)
    try:
        """ Remove a netns for running docker container """
        runCommand(log, "ip netns delete %s" % docker_container_pid)
        runCommand(log, "ip link delete %s" % vpn2ns)
    except:
        raise Exception("Can't remove netns %s doesn't exist" %
                        docker_container_pid)
Ejemplo n.º 5
0
    def _detach_evpn2ipvpn(self, ipvpn):
        """
        Symmetric to _attach_evpn2ipvpn
        """
        (evpn_if, ipvpn_if, evpnInstance, managed) = self._evpn_ipvpn_ifs[ipvpn]

        if not ipvpn.hasEnpoint(ipvpn_if):
            # TODO: check that this evpn instance is still up and running
            evpnInstance.gatewayPortDown(evpn_if)

            # cleanup veth pair
            if managed:
                runCommand(log, "ip link delete %s" % evpn_if)

            del self._evpn_ipvpn_ifs[ipvpn]
Ejemplo n.º 6
0
def pidof_docker_container(container_id):
    """ get PID """
    (output, _) = runCommand(log, "docker inspect -f '{{.State.Pid}}' %s" % container_id)
    if output[0] == "":
        raise Exception("Docker container doesn't exist: %s" % output)
    pid = output[0]
    return pid
Ejemplo n.º 7
0
    def _detach_evpn2ipvpn(self, ipvpn):
        """
        Symmetric to _attach_evpn2ipvpn
        """
        (evpn_if, ipvpn_if, evpnInstance,
         managed) = self._evpn_ipvpn_ifs[ipvpn]

        if not ipvpn.hasEnpoint(ipvpn_if):
            # TODO: check that this evpn instance is still up and running
            evpnInstance.gatewayPortDown(evpn_if)

            # cleanup veth pair
            if managed:
                runCommand(log, "ip link delete %s" % evpn_if)

            del self._evpn_ipvpn_ifs[ipvpn]
Ejemplo n.º 8
0
def pidof_docker_container(container_id):
    """ get PID """
    (output,
     _) = runCommand(log,
                     "docker inspect -f '{{.State.Pid}}' %s" % container_id)
    if output[0] == "":
        raise Exception("Docker container doesn't exist: %s" % output)
    pid = output[0]
    return pid
Ejemplo n.º 9
0
def getNetNSInterfaceMac(namespace, interface):
    # options.mac is the MAC address of the ns2vpn interface
    cmd = "ip netns exec %s ip -o link show %s | perl -pe 's|.* " \
        "link/ether ([^ ]+) .*|$1|' 2>/dev/null"
    (output, _) = runCommand(log, cmd % (namespace, interface))
    if "does not exist" in output[0]:
        raise Exception("special netns interface does not exist: %s" % output)
    mac = output[0]

    return mac
Ejemplo n.º 10
0
def getNetNSInterfaceMac(namespace, interface):
    # options.mac is the MAC address of the ns2vpn interface
    cmd = "ip netns exec %s ip -o link show %s | perl -pe 's|.* " \
        "link/ether ([^ ]+) .*|$1|' 2>/dev/null"
    (output, _) = runCommand(log, cmd % (namespace, interface))
    if "does not exist" in output[0]:
        raise Exception("special netns interface does not exist: %s" % output)
    mac = output[0]

    return mac
Ejemplo n.º 11
0
def create_veth_pair(vpn_interface, ns_interface, ns_name):
    runCommand(log,
               "ip netns exec %s ip link delete %s" % (ns_name, ns_interface),
               raiseExceptionOnError=False,
               acceptableReturnCodes=[0, 1])
    # in case the interface was previously attached to OVS,
    # we need to remove that, or when then interface is re-created
    # OVS will take it back!
    runCommand(log,
               "ovs-vsctl del-port %s" % vpn_interface,
               raiseExceptionOnError=False,
               acceptableReturnCodes=[0, 1])
    runCommand(log,
               "ip link delete %s" % vpn_interface,
               raiseExceptionOnError=False,
               acceptableReturnCodes=[0, 1])
    runCommand(log,
               "ip link add %s type veth peer name %s netns %s" %
               (vpn_interface, ns_interface, ns_name),
               raiseExceptionOnError=False)
    runCommand(log, "ip link set dev %s up" % vpn_interface)
    runCommand(log, "ip link set dev %s mtu %d" % (vpn_interface, DEFAULT_MTU))
    runCommand(
        log,
        "ip netns exec %s ip link set dev %s up" % (ns_name, ns_interface))
Ejemplo n.º 12
0
 def _runCommand(self, command, *args, **kwargs):
     return runCommand(self.log, command, *args, **kwargs)
Ejemplo n.º 13
0
    def _attach_evpn2ipvpn(self, localPort, ipvpnInstance):
        """ Assuming localPort indicates no real interface but only
        an EVPN, this method will create a pair of twin interfaces, one
        to plug in the EVPN, the other to plug in the IPVPN.

        The localPort dict will be modified so that the 'linuxif' indicates
        the name of the interface to plug in the IPVPN.

        The EVPN instance will be notified so that it forwards traffic
        destinated to the gateway on the interface toward the IPVPN.
        """
        assert ('evpn' in localPort)

        if 'id' not in localPort['evpn']:
            raise Exception("Missing parameter 'id' :an external EVPN "
                            "instance id must be specified for an EVPN "
                            "attachment")

        try:
            evpn = self.vpnInstances[localPort['evpn']['id']]
        except:
            raise Exception("The specified evpn instance does not exist (%s)" %
                            localPort['evpn'])

        if (evpn.type != "evpn"):
            raise Exception("The specified instance to plug is not an epnv"
                            "instance (is %s instead)" % evpn.type)

        if ipvpnInstance in self._evpn_ipvpn_ifs:
            (evpn_if, ipvpn_if, evpn, managed) = \
                self._evpn_ipvpn_ifs[ipvpnInstance]

            if not (localPort['evpn']['id'] == evpn.externalInstanceId):
                raise Exception('Trying to plug into an IPVPN a new E-VPN '
                                'while one is already plugged in')
            else:
                # do nothing
                log.warning('Trying to plug an E-VPN into an IPVPN, but it was'
                            'already done')
                localPort['linuxif'] = ipvpn_if
                return

        #  detect if this evpn is already plugged into an IPVPN
        if evpn.hasGatewayPort():
            raise Exception("Trying to plug E-VPN into an IPVPN, but this EVPN"
                            " is already plugged into an IPVPN")

        if ('linuxif' in localPort and localPort['linuxif']):
            raise Exception("Cannot specify an attachment with both a linuxif "
                            "and an evpn")

        if 'ovs_port_name' in localPort['evpn']:
            try:
                assert (localPort['ovs']['plugged'])
                assert (localPort['ovs']['port_name']
                        or localPort['ovs']['port_number'])
            except:
                raise Exception("Using ovs_port_name in EVPN/IPVPN attachment"
                                " requires specifying the corresponding OVS"
                                " port, which must also be pre-plugged")

            evpn_if = localPort['evpn']['ovs_port_name']

            # we assume in this case that the E-VPN interface is already
            # plugged into the E-VPN bridge
            managed = False
        else:
            evpn_if = "evpn%d-ipvpn%d" % (evpn.instanceId,
                                          ipvpnInstance.instanceId)
            ipvpn_if = "ipvpn%d-evpn%d" % (ipvpnInstance.instanceId,
                                           evpn.instanceId)

            # FIXME: do it only if not existing already...
            log.info("Creating veth pair %s %s ", evpn_if, ipvpn_if)

            # delete the interfaces if they exist already
            runCommand(log,
                       "ip link delete %s" % evpn_if,
                       acceptableReturnCodes=[0, 1])
            runCommand(log,
                       "ip link delete %s" % ipvpn_if,
                       acceptableReturnCodes=[0, 1])

            runCommand(
                log,
                "ip link add %s type veth peer name %s" % (evpn_if, ipvpn_if))

            runCommand(log, "ip link set %s up" % evpn_if)
            runCommand(log, "ip link set %s up" % ipvpn_if)
            managed = True

        localPort['linuxif'] = ipvpn_if

        evpn.setGatewayPort(evpn_if, ipvpnInstance)

        self._evpn_ipvpn_ifs[ipvpnInstance] = (evpn_if, ipvpn_if, evpn,
                                               managed)
Ejemplo n.º 14
0
def createSpecialNetNSPort(options):
    print "Will plug local namespace %s into network" % options.netns

    # create namespace
    runCommand(log, "ip netns add %s" %
               options.netns, raiseExceptionOnError=False)

    # create veth pair and move one into namespace
    if options.ovs_vlan:
        create_veth_pair(options.if2netns, "ns2vpn-raw", options.netns)

        runCommand(log, "ip netns exec %s ip link add link ns2vpn-raw "
                   "name %s type vlan id %d"
                   % (options.netns, options.if2vpn, options.ovs_vlan))
        runCommand(log, "ip netns exec %s ip link set %s up"
                   % (options.netns, options.if2vpn))
    else:
        create_veth_pair(options.if2netns, options.if2vpn, options.netns)

    if options.mac:
        runCommand(log, "ip netns exec %s ip link set %s address %s"
                   % (options.netns, options.if2vpn, options.mac))

    runCommand(log, "ip netns exec %s ip addr add %s dev %s" %
               (options.netns, options.ip, options.if2vpn),
               raiseExceptionOnError=False)

    runCommand(log, "ip netns exec %s ip route add default dev %s via %s" %
               (options.netns, options.if2vpn, options.gw_ip),
               raiseExceptionOnError=False)

    runCommand(log, "ip netns exec %s ip link set %s mtu 1420" %
               (options.netns, options.if2vpn),
               raiseExceptionOnError=False)
Ejemplo n.º 15
0
def create_veth_pair(vpn_interface, ns_interface, ns_name):
    runCommand(log, "ip netns exec %s ip link delete %s" %
               (ns_name, ns_interface), raiseExceptionOnError=False)
    runCommand(log, "ip link delete %s" %
               vpn_interface, raiseExceptionOnError=False)
    runCommand(log, "ip link add %s type veth peer name %s netns %s" %
               (vpn_interface, ns_interface, ns_name),
               raiseExceptionOnError=False)
    runCommand(log, "ip link set dev %s up" % vpn_interface)
    runCommand(log, "ip link set dev %s mtu %d" % (vpn_interface, DEFAULT_MTU))
    runCommand(log, "ip netns exec %s ip link set dev %s up" %
               (ns_name, ns_interface))
Ejemplo n.º 16
0
def main():
    usage = "usage: %prog [--attach|--detach] --network-type (ipvpn|evpn) "\
        "--port (<port>|netns) --ip <ip>[/<mask>] [options] (see --help)"
    parser = OptionParser(usage)

    parser.add_option("--attach", dest="operation",
                      action="store_const", const="attach",
                      help="attach local port")
    parser.add_option("--detach", dest="operation",
                      action="store_const", const="detach",
                      help="detach local port")

    parser.add_option("--network-type", dest="network_type",
                      help="network type (ipvpn or evpn)",
                      choices=["ipvpn", "evpn"])
    parser.add_option("--vpn-instance-id", dest="vpn_instance_id",
                      help="UUID for the network instance "
                      "(default: %default-(ipvpn|evpn))",
                      default=DEFAULT_VPN_INSTANCE_ID)
    parser.add_option("--port", dest="port",
                      help="local port to attach/detach (use special port "
                      "'netns[:if]' to have an interface to a local network "
                      "namespace attached/detached "
                      "[with 'if' as the name of the interface to the netns]")

    parser.add_option("--rt", dest="routeTargets",
                      help="route target [default: 64512:0] (can be "
                      "specified multiple times)", default=[], action="append")
    parser.add_option("--import-rt", dest="importOnlyRouteTargets",
                      help="import-only route target (can be specified"
                      "multiple times)", default=[], action="append")
    parser.add_option("--export-rt", dest="exportOnlyRouteTargets",
                      help="export-only route target (can be specified"
                      "multiple times)", default=[], action="append")

    parser.add_option("--ip", dest="ip",
                      help="IP prefix / mask (mask defaults to /24)")
    parser.add_option("--gateway-ip", dest="gw_ip",
                      help="IP address of network gateway (optional, "
                      "defaults to last IP in range)")
    parser.add_option("--mac", dest="mac",
                      help="MAC address (required for evpn if port"
                      " is not 'netns')")

    parser.set_defaults(advertiseSubnet=False)
    parser.add_option("--advertise-singleton", action="store_false",
                      dest="advertiseSubnet",
                      help="advertise IP address as a /32 (default)")

    parser.add_option("--advertise-subnet", action="store_true",
                      dest="advertiseSubnet",
                      help="advertise the whole IP subnet")

    parser.add_option("--ovs-preplug", action="store_true", dest="ovs_preplug",
                      default=False, help="should we prealably plug the port "
                      "into an OVS bridge")
    parser.add_option("--ovs-bridge", dest="bridge", default="br-int",
                      help="if preplug, specifies which OVS bridge to use"
                      " (default: %default)")
    parser.add_option("--ovs-vlan", dest="ovs_vlan", type='int',
                      help="if specified, only this VLAN from the OVS "
                      "interface will be attached to the VPN instance "
                      "(optional)")

    parser.add_option("--netns", dest="netns",
                      help="name of network namespace (optional, for use with"
                      " --port netns)")
    parser.add_option("--if2vpn", dest="if2vpn", default=NS2VPN_DEFAULT_IFNAME,
                      help="name of interface in netns toward VPN"
                      "defaults to %default "
                      "(optional, for use with --port netns)")

    parser.add_option("--readv-from-rt", dest="reAdvFromRTs",
                      help="enables route readvertisement from these RTs,"
                      " works in conjunction with --readv-to-rt",
                      default=[], action="append")

    parser.add_option("--readv-to-rt", dest="reAdvToRTs",
                      help="enables route readvertisement to these RTs,"
                      " works in conjunction with --readv-from-rt",
                      default=[], action="append")

    (options, _) = parser.parse_args()

    if not(options.operation):
        parser.error("Need to specify --attach or --detach")

    if not(options.port):
        parser.error("Need to specify --port <localport>")

    if not(options.network_type):
        parser.error("Need to specify --network-type")

    if not(options.ip):
        parser.error("Need to specify --ip")

    if (len(options.routeTargets) == 0 and
            not (options.importOnlyRouteTargets
                 or options.exportOnlyRouteTargets)):
        if options.network_type == "ipvpn":
            options.routeTargets = ["64512:512"]
        else:
            options.routeTargets = ["64512:513"]

    importRTs = copy(options.routeTargets or [])
    for rt in options.importOnlyRouteTargets:
        importRTs.append(rt)

    exportRTs = copy(options.routeTargets or [])
    for rt in options.exportOnlyRouteTargets:
        exportRTs.append(rt)

    if not re.match('.*/[0-9]+$', options.ip):
        options.ip = options.ip + "/24"

    if not(options.gw_ip):
        net = IPNetwork(options.ip)
        print "using %s as gateway address" % str(net[-2])
        options.gw_ip = str(net[-2])

    if options.vpn_instance_id == DEFAULT_VPN_INSTANCE_ID:
        options.vpn_instance_id = "%s-%s" % (
            options.network_type, options.vpn_instance_id)

    if options.port.startswith("netns"):

        if not options.netns:
            options.netns = options.vpn_instance_id

        try:
            (_, options.if2netns) = options.port.split(":")
        except:
            options.if2netns = get_vpn2ns_if_name(options.netns)

        if options.operation == "attach":
            createSpecialNetNSPort(options)

        options.port = options.if2netns
        options.mac = get_device_mac(lambda *args: runCommand(log, *args),
                                     options.if2vpn, options.netns)

        print "Local port: %s (%s)" % (options.port, options.mac)
        runCommand(log, "ip link show %s" % options.port)

    local_port = {}
    if options.port[:5] == "evpn:":
        if (options.network_type == "ipvpn"):
            print "will plug evpn %s into the IPVPN" % options.port[5:]
            local_port['evpn'] = {'id': options.port[5:]}
        else:
            raise Exception("Can only plug an evpn into an ipvpn")
    else:
        local_port['linuxif'] = options.port

        # currently our only the MPLS OVS driver for ipvpn requires preplug
        if (options.ovs_preplug and options.network_type == "ipvpn"):
            print "pre-plugging %s into %s" % (options.port,
                                               options.bridge)
            runCommand(log, "ovs-vsctl del-port %s %s" %
                       (options.bridge, options.port),
                       raiseExceptionOnError=False)
            runCommand(log, "ovs-vsctl add-port %s %s" %
                       (options.bridge, options.port))

            local_port['ovs'] = {'port_name': options.port,
                                 'plugged': True}

            if options.ovs_vlan:
                local_port['ovs']['vlan'] = options.ovs_vlan

    if not(options.mac):
        if options.network_type == "ipvpn":
            options.mac = "52:54:00:99:99:22"
        else:
            parser.error("Need to specify --mac for an EVPN network "
                         "attachment if port is not 'netns'")

    readvertise = None
    if options.reAdvToRTs:
        readvertise = {"from_rt": options.reAdvFromRTs,
                       "to_rt": options.reAdvToRTs}

    json_data = json.dumps({"import_rt":  importRTs,
                            "export_rt":  exportRTs,
                            "local_port":  local_port,
                            "vpn_instance_id":  options.vpn_instance_id,
                            "vpn_type":    options.network_type,
                            "gateway_ip":  options.gw_ip,
                            "mac_address": options.mac,
                            "ip_address":  options.ip,
                            "advertise_subnet": options.advertiseSubnet,
                            "readvertise": readvertise
                            })

    print "request: %s" % json_data

    os.environ['NO_PROXY'] = "127.0.0.1"
    req = urllib2.Request("http://127.0.0.1:8082/%s_localport" %
                          options.operation, json_data,
                          {'Content-Type': 'application/json'})
    try:
        response = urllib2.urlopen(req)
        response_content = response.read()
        response.close()

        print "response: %d %s" % (response.getcode(), response_content)
    except urllib2.HTTPError as e:
        error_content = e.read()
        print "   %s" % error_content
        sys.exit("error %d, reason: %s" % (e.code, e.reason))
Ejemplo n.º 17
0
def createSpecialNetNSPort(options):
    print "Will plug local namespace %s into network" % options.netns

    # create namespace
    runCommand(log,
               "ip netns add %s" % options.netns,
               raiseExceptionOnError=False)

    # create veth pair and move one into namespace
    if options.ovs_vlan:
        create_veth_pair(options.if2netns, "ns2vpn-raw", options.netns)

        runCommand(
            log, "ip netns exec %s ip link add link ns2vpn-raw "
            "name %s type vlan id %d" %
            (options.netns, options.if2vpn, options.ovs_vlan))
        runCommand(
            log, "ip netns exec %s ip link set %s up" %
            (options.netns, options.if2vpn))
    else:
        create_veth_pair(options.if2netns, options.if2vpn, options.netns)

    if options.mac:
        runCommand(
            log, "ip netns exec %s ip link set %s address %s" %
            (options.netns, options.if2vpn, options.mac))

    runCommand(log,
               "ip netns exec %s ip addr add %s dev %s" %
               (options.netns, options.ip, options.if2vpn),
               raiseExceptionOnError=False)

    runCommand(log,
               "ip netns exec %s ip route add default dev %s via %s" %
               (options.netns, options.if2vpn, options.gw_ip),
               raiseExceptionOnError=False)

    runCommand(log,
               "ip netns exec %s ip link set %s mtu 1420" %
               (options.netns, options.if2vpn),
               raiseExceptionOnError=False)
Ejemplo n.º 18
0
def create_veth_pair(vpn_interface, ns_interface, ns_name):
    runCommand(log,
               "ip netns exec %s ip link delete %s" % (ns_name, ns_interface),
               raiseExceptionOnError=False)
    runCommand(log,
               "ip link delete %s" % vpn_interface,
               raiseExceptionOnError=False)
    runCommand(log,
               "ip link add %s type veth peer name %s netns %s" %
               (vpn_interface, ns_interface, ns_name),
               raiseExceptionOnError=False)
    runCommand(log, "ip link set dev %s up" % vpn_interface)
    runCommand(log, "ip link set dev %s mtu %d" % (vpn_interface, DEFAULT_MTU))
    runCommand(
        log,
        "ip netns exec %s ip link set dev %s up" % (ns_name, ns_interface))
Ejemplo n.º 19
0
def main():
    usage = "usage: %prog [--attach|--detach] --network-type (ipvpn|evpn) "\
        "--port (<port>|netns) --ip <ip>[/<mask>] [options] (see --help)"
    parser = OptionParser(usage)

    parser.add_option("--attach",
                      dest="operation",
                      action="store_const",
                      const="attach",
                      help="attach local port")
    parser.add_option("--detach",
                      dest="operation",
                      action="store_const",
                      const="detach",
                      help="detach local port")

    parser.add_option("--network-type",
                      dest="network_type",
                      help="network type (ipvpn or evpn)",
                      choices=["ipvpn", "evpn"])
    parser.add_option("--vpn-instance-id",
                      dest="vpn_instance_id",
                      help="UUID for the network instance "
                      "(default: %default-(ipvpn|evpn))",
                      default=DEFAULT_VPN_INSTANCE_ID)
    parser.add_option("--port",
                      dest="port",
                      help="local port to attach/detach (use special port "
                      "'netns[:if]' to have an interface to a local network "
                      "namespace attached/detached "
                      "[with 'if' as the name of the interface to the netns]")

    parser.add_option("--rt",
                      dest="routeTargets",
                      help="route target [default: 64512:0] (can be "
                      "specified multiple times)",
                      default=[],
                      action="append")
    parser.add_option("--import-rt",
                      dest="importOnlyRouteTargets",
                      help="import-only route target (can be specified"
                      "multiple times)",
                      default=[],
                      action="append")
    parser.add_option("--export-rt",
                      dest="exportOnlyRouteTargets",
                      help="export-only route target (can be specified"
                      "multiple times)",
                      default=[],
                      action="append")

    parser.add_option("--ip",
                      dest="ip",
                      help="IP prefix / mask (mask defaults to /24)")
    parser.add_option("--gateway-ip",
                      dest="gw_ip",
                      help="IP address of network gateway (optional, "
                      "defaults to last IP in range)")
    parser.add_option("--mac",
                      dest="mac",
                      help="MAC address (required for evpn if port"
                      " is not 'netns')")

    parser.set_defaults(advertiseSubnet=False)
    parser.add_option("--advertise-singleton",
                      action="store_false",
                      dest="advertiseSubnet",
                      help="advertise IP address as a /32 (default)")

    parser.add_option("--advertise-subnet",
                      action="store_true",
                      dest="advertiseSubnet",
                      help="advertise the whole IP subnet")

    parser.add_option("--ovs-preplug",
                      action="store_true",
                      dest="ovs_preplug",
                      default=False,
                      help="should we prealably plug the port "
                      "into an OVS bridge")
    parser.add_option("--ovs-bridge",
                      dest="bridge",
                      default="br-int",
                      help="if preplug, specifies which OVS bridge to use"
                      " (default: %default)")
    parser.add_option("--ovs-vlan",
                      dest="ovs_vlan",
                      type='int',
                      help="if specified, only this VLAN from the OVS "
                      "interface will be attached to the VPN instance "
                      "(optional)")

    parser.add_option("--netns",
                      dest="netns",
                      help="name of network namespace (optional, for use with"
                      " --port netns)")
    parser.add_option("--if2vpn",
                      dest="if2vpn",
                      default=NS2VPN_DEFAULT_IFNAME,
                      help="name of interface in netns toward VPN"
                      "defaults to %default "
                      "(optional, for use with --port netns)")

    parser.add_option("--readv-from-rt",
                      dest="reAdvFromRTs",
                      help="enables route readvertisement from these RTs,"
                      " works in conjunction with --readv-to-rt",
                      default=[],
                      action="append")

    parser.add_option("--readv-to-rt",
                      dest="reAdvToRTs",
                      help="enables route readvertisement to these RTs,"
                      " works in conjunction with --readv-from-rt",
                      default=[],
                      action="append")

    (options, _) = parser.parse_args()

    if not (options.operation):
        parser.error("Need to specify --attach or --detach")

    if not (options.port):
        parser.error("Need to specify --port <localport>")

    if not (options.network_type):
        parser.error("Need to specify --network-type")

    if not (options.ip):
        parser.error("Need to specify --ip")

    if (len(options.routeTargets) == 0
            and not (options.importOnlyRouteTargets
                     or options.exportOnlyRouteTargets)):
        if options.network_type == "ipvpn":
            options.routeTargets = ["64512:512"]
        else:
            options.routeTargets = ["64512:513"]

    importRTs = copy(options.routeTargets or [])
    for rt in options.importOnlyRouteTargets:
        importRTs.append(rt)

    exportRTs = copy(options.routeTargets or [])
    for rt in options.exportOnlyRouteTargets:
        exportRTs.append(rt)

    if not re.match('.*/[0-9]+$', options.ip):
        options.ip = options.ip + "/24"

    if not (options.gw_ip):
        net = IPNetwork(options.ip)
        print "using %s as gateway address" % str(net[-2])
        options.gw_ip = str(net[-2])

    if options.vpn_instance_id == DEFAULT_VPN_INSTANCE_ID:
        options.vpn_instance_id = "%s-%s" % (options.network_type,
                                             options.vpn_instance_id)

    if options.port.startswith("netns"):

        if not options.netns:
            options.netns = options.vpn_instance_id

        try:
            (_, options.if2netns) = options.port.split(":")
        except:
            options.if2netns = get_vpn2ns_if_name(options.netns)

        if options.operation == "attach":
            createSpecialNetNSPort(options)

        options.port = options.if2netns
        options.mac = getNetNSInterfaceMac(options.netns, options.if2vpn)

        print "Local port: %s (%s)" % (options.port, options.mac)
        runCommand(log, "ip link show %s" % options.port)

    local_port = {}
    if options.port[:5] == "evpn:":
        if (options.network_type == "ipvpn"):
            print "will plug evpn %s into the IPVPN" % options.port[5:]
            local_port['evpn'] = {'id': options.port[5:]}
        else:
            raise Exception("Can only plug an evpn into an ipvpn")
    else:
        local_port['linuxif'] = options.port

        # currently our only the MPLS OVS driver for ipvpn requires preplug
        if (options.ovs_preplug and options.network_type == "ipvpn"):
            print "pre-plugging %s into %s" % (options.port, options.bridge)
            runCommand(log,
                       "ovs-vsctl del-port %s %s" %
                       (options.bridge, options.port),
                       raiseExceptionOnError=False)
            runCommand(
                log,
                "ovs-vsctl add-port %s %s" % (options.bridge, options.port))

            local_port['ovs'] = {'port_name': options.port, 'plugged': True}

            if options.ovs_vlan:
                local_port['ovs']['vlan'] = options.ovs_vlan

    if not (options.mac):
        if options.network_type == "ipvpn":
            options.mac = "52:54:00:99:99:22"
        else:
            parser.error("Need to specify --mac for an EVPN network "
                         "attachment if port is not 'netns'")

    readvertise = None
    if options.reAdvToRTs:
        readvertise = {
            "from_rt": options.reAdvFromRTs,
            "to_rt": options.reAdvToRTs
        }

    json_data = json.dumps({
        "import_rt": importRTs,
        "export_rt": exportRTs,
        "local_port": local_port,
        "vpn_instance_id": options.vpn_instance_id,
        "vpn_type": options.network_type,
        "gateway_ip": options.gw_ip,
        "mac_address": options.mac,
        "ip_address": options.ip,
        "advertise_subnet": options.advertiseSubnet,
        "readvertise": readvertise
    })

    print "request: %s" % json_data

    os.environ['NO_PROXY'] = "127.0.0.1"
    req = urllib2.Request(
        "http://127.0.0.1:8082/%s_localport" % options.operation, json_data,
        {'Content-Type': 'application/json'})
    try:
        response = urllib2.urlopen(req)
        response_content = response.read()
        response.close()

        print "response: %d %s" % (response.getcode(), response_content)
    except urllib2.HTTPError as e:
        error_content = e.read()
        print "   %s" % error_content
        sys.exit("error %d, reason: %s" % (e.code, e.reason))
Ejemplo n.º 20
0
    def _attach_evpn2ipvpn(self, localPort, ipvpnInstance):
        """ Assuming localPort indicates no real interface but only
        an EVPN, this method will create a pair of twin interfaces, one
        to plug in the EVPN, the other to plug in the IPVPN.

        The localPort dict will be modified so that the 'linuxif' indicates
        the name of the interface to plug in the IPVPN.

        The EVPN instance will be notified so that it forwards traffic
        destinated to the gateway on the interface toward the IPVPN.
        """
        assert "evpn" in localPort

        if "id" not in localPort["evpn"]:
            raise Exception(
                "Missing parameter 'id' :an external EVPN " "instance id must be specified for an EVPN " "attachment"
            )

        try:
            evpn = self.vpnInstances[localPort["evpn"]["id"]]
        except:
            raise Exception("The specified evpn instance does not exist (%s)" % localPort["evpn"])

        if evpn.type != "evpn":
            raise Exception("The specified instance to plug is not an evpn" "instance (is %s instead)" % evpn.type)

        if ipvpnInstance in self._evpn_ipvpn_ifs:
            (evpn_if, ipvpn_if, evpn, managed) = self._evpn_ipvpn_ifs[ipvpnInstance]

            if not (localPort["evpn"]["id"] == evpn.externalInstanceId):
                raise Exception("Trying to plug into an IPVPN a new E-VPN " "while one is already plugged in")
            else:
                # do nothing
                log.warning("Trying to plug an E-VPN into an IPVPN, but it was" "already done")
                localPort["linuxif"] = ipvpn_if
                return

        #  detect if this evpn is already plugged into an IPVPN
        if evpn.hasGatewayPort():
            raise Exception("Trying to plug E-VPN into an IPVPN, but this EVPN" " is already plugged into an IPVPN")

        if "linuxif" in localPort and localPort["linuxif"]:
            raise Exception("Cannot specify an attachment with both a linuxif " "and an evpn")

        if "ovs_port_name" in localPort["evpn"]:
            try:
                assert localPort["ovs"]["plugged"]
                assert localPort["ovs"]["port_name"] or localPort["ovs"]["port_number"]
            except:
                raise Exception(
                    "Using ovs_port_name in EVPN/IPVPN attachment"
                    " requires specifying the corresponding OVS"
                    " port, which must also be pre-plugged"
                )

            evpn_if = localPort["evpn"]["ovs_port_name"]

            # we assume in this case that the E-VPN interface is already
            # plugged into the E-VPN bridge
            managed = False
        else:
            evpn_if = "evpn%d-ipvpn%d" % (evpn.instanceId, ipvpnInstance.instanceId)
            ipvpn_if = "ipvpn%d-evpn%d" % (ipvpnInstance.instanceId, evpn.instanceId)

            # FIXME: do it only if not existing already...
            log.info("Creating veth pair %s %s ", evpn_if, ipvpn_if)

            # delete the interfaces if they exist already
            runCommand(log, "ip link delete %s" % evpn_if, acceptableReturnCodes=[0, 1])
            runCommand(log, "ip link delete %s" % ipvpn_if, acceptableReturnCodes=[0, 1])

            runCommand(log, "ip link add %s type veth peer name %s" % (evpn_if, ipvpn_if))

            runCommand(log, "ip link set %s up" % evpn_if)
            runCommand(log, "ip link set %s up" % ipvpn_if)
            managed = True

        localPort["linuxif"] = ipvpn_if

        evpn.setGatewayPort(evpn_if, ipvpnInstance)

        self._evpn_ipvpn_ifs[ipvpnInstance] = (evpn_if, ipvpn_if, evpn, managed)
 def _runCommand(self, command, *args, **kwargs):
     return runCommand(self.log, command, *args, **kwargs)