def __init__(self, *args, **kwargs):
        VPNInstanceDataplane.__init__(self, *args)

        self.arpNetNS = ("%s%d" %
                         (ARPNETNS_PREFIX, self.instanceId))[:LINUX_DEV_LEN]

        # Initialize dict where we store info on OVS ports (port numbers and
        # bound IP address)
        self._ovsPortInfo = dict()

        # Find ethX MPLS interface MAC address
        if not self.driver.useGRE:
            self.mplsIfMacAddress = net_utils.get_device_mac(
                self._runCommand, self.driver.mpls_interface)
        else:
            self.mplsIfMacAddress = None

        self.bridge = self.driver.bridge

        self.fallback = None
        self.push_vlan_action = None

        if self.driver.proxy_arp:
            self._initARPNetNS()

        # Create VRF-specific OVS patch ports
        self.log.debug(
            "Creating VRF patch ports and mapping traffic to gateway...")
        self.patchPortIn = 'ipvpn%d-pp-in' % self.instanceId
        self.patchPortOut = 'ipvpn%d-pp-out' % self.instanceId
        self._runCommand("ovs-vsctl --may-exist add-port %s %s -- "
                         "set Interface %s type=patch options:peer=%s" %
                         (self.bridge, self.patchPortIn, self.patchPortIn,
                          self.patchPortOut))
        self._runCommand("ovs-vsctl --may-exist add-port %s %s -- "
                         "set Interface %s type=patch options:peer=%s" %
                         (self.bridge, self.patchPortOut, self.patchPortOut,
                          self.patchPortIn))

        self.patchPortInNumber = self.driver.find_ovs_port(self.patchPortIn)
        self.patchPortOutNumber = self.driver.find_ovs_port(self.patchPortOut)

        if self.driver.proxy_arp:
            # Map traffic from patch port to gateway
            self._ovs_flow_add(
                'in_port=%s,ip,nw_dst=%s' %
                (self.patchPortInNumber, self.gatewayIP),
                'output:%s' % self.arpNetNSPort, self.driver.ovs_table_vrfs)
Esempio n. 2
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))
Esempio n. 3
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))
Esempio n. 4
0
    def __init__(self, *args, **kwargs):
        VPNInstanceDataplane.__init__(self, *args)

        self.arpNetNS = ("%s-vrf%d" %
                         (ARPNETNS_PREFIX, self.instanceId))[:LINUX_DEV_LEN]

        # Initialize dict where we store info on OVS ports (port numbers and
        # bound IP address)
        self._ovsPortInfo = dict()

        # Find ethX MPLS interface MAC address
        if not self.driver.useGRE:
            self.mplsIfMacAddress = get_device_mac(
                self._runCommand,
                self.driver.mpls_interface)
        else:
            self.mplsIfMacAddress = None

        self.bridge = self.driver.bridge

        self.log.info("VRF %d: Initializing network namespace %s for ARP "
                      "proxing", self.instanceId, self.arpNetNS)
        # Get names of veth pair devices between OVS and network namespace
        ovsbr_to_proxyarp_ns = self.driver.get_ovsbr2arpns_if(
            self.arpNetNS)

        if not self._arpNetNsExists():
            self.log.debug("VRF network namespace doesn't exist, creating...")
            # Create network namespace
            self._runCommand("ip netns add %s" % self.arpNetNS)

            # Set up veth pair devices between OVS and ARP network namespace
            self._create_arpnetns_veth_pair(ovsbr_to_proxyarp_ns,
                                            PROXYARP2OVS_IF)

            # Retrieve broadcast IP address
            ip = IPNetwork("%s/%s" % (self.gatewayIP, self.mask))
            broadcastIP = str(ip.broadcast)

            # Set up network namespace interface as gateway
            self._runCommand("ip netns exec %s ip addr add %s/%s broadcast %s"
                             " dev %s" %
                             (self.arpNetNS, self.gatewayIP,
                              self.mask, broadcastIP, PROXYARP2OVS_IF),
                             raiseExceptionOnError=True)

            # Setup IP forwarding
            self._runCommand("ip netns exec %s sh -c \"echo 1 > /proc/sys"
                             "/net/ipv4/ip_forward\"" % self.arpNetNS)
            self._runCommand("ip netns exec %s sh -c \"echo 1 > /proc/sys/net"
                             "/ipv4/conf/all/forwarding\"" % self.arpNetNS)

            # Setup ARP proxying
            self._runCommand("ip netns exec %s sh -c \"echo 1 > /proc/sys/net"
                             "/ipv4/conf/%s/proxy_arp\"" %
                             (self.arpNetNS, PROXYARP2OVS_IF))
            self._runCommand("ip netns exec %s sh -c \"echo 1 > /proc/sys/net"
                             "/ipv4/conf/%s/proxy_arp_pvlan\"" %
                             (self.arpNetNS, PROXYARP2OVS_IF))
        else:
            self.log.debug("VRF network namespace already exists...")

        # OVS port number for the port toward the proxy ARP netns
        self.arpNetNSPort = self.driver.find_ovs_port(ovsbr_to_proxyarp_ns)

        # Find gateway ("network namespace to OVS" port) MAC address
        self.gwMacAddress = get_device_mac(self._runCommand,
                                           PROXYARP2OVS_IF,
                                           self.arpNetNS)

        # Create OVS patch ports
        self.log.debug(
            "Creating VRF patch ports and mapping traffic to gateway...")
        self.patchPortIn = 'ipvpn%d-pp-in' % self.instanceId
        self.patchPortOut = 'ipvpn%d-pp-out' % self.instanceId
        self._runCommand("ovs-vsctl --may-exist add-port %s %s -- "
                         "set Interface %s type=patch options:peer=%s" %
                         (self.bridge, self.patchPortIn,
                          self.patchPortIn, self.patchPortOut))
        self._runCommand("ovs-vsctl --may-exist add-port %s %s -- "
                         "set Interface %s type=patch options:peer=%s" %
                         (self.bridge, self.patchPortOut,
                          self.patchPortOut, self.patchPortIn))

        self.patchPortInNumber = self.driver.find_ovs_port(self.patchPortIn)
        self.patchPortOutNumber = self.driver.find_ovs_port(self.patchPortOut)
        # Map traffic from patch port to gateway
        self._ovs_flow_add('in_port=%s,ip,nw_dst=%s' % (self.patchPortInNumber,
                                                        self.gatewayIP),
                           'output:%s' % self.arpNetNSPort,
                           self.driver.ovs_table_vrfs)