Source code for smc.elements.netlink

#  Licensed under the Apache License, Version 2.0 (the "License"); you may
#  not use this file except in compliance with the License. You may obtain
#  a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#  License for the specific language governing permissions and limitations
#  under the License.
"""
NetLink elements are used to represent alternative routes that lead to the
same destination IP addresses.

NetLinks usually represent Internet connections, but can be used for other
communications links as well.

You can use a single Router if a single route is enough for routing traffic
to a network through an interface or an aggregated link. If you want to create
separate routes for traffic to a network through two or more interfaces, you
must use NetLinks.

To use traffic handlers, you must first create the netlink type required, then
add this to the engine routing node.

Creating a static netlink element::

    StaticNetlink.create(
        name='netlink',
        gateway=Router('routerfoo'),
        network=[Network('mynetwork')],
        domain_server_address=['8.8.8.8', '8.8.4.4'],
        probe_address=['1.1.1.254'],
        comment='foobar')

Add the netlink to the desired routing interface::

    engine = Engine('vm')
    rnode = engine.routing.get(0) #interface 0
    rnode.add_traffic_handler(
        netlink=StaticNetlink('mynetlink'),
        netlink_gw=[Router('myrtr')])

.. seealso:: :class:`smc.core.route.Routing.add_traffic_handler`

Creating Multilink's require that you first have StaticNetlink or DynamicNetlink
elements. Once you have this created, you can create a multilink in a two step
process.

First create the multilink members specifying the created netlinks. A multilink
member encapsulates the creation process and collects the required information for
each netlink such as ip_range to use for source NAT (static netlink only) and
the network role::

    member = MultilinkMember.create(
        StaticNetlink('netlink1'), ip_range='1.1.1.1-1.1.1.2', netlink_role='active')

    member1 = MultilinkMember.create(
        StaticNetlink('netlink2'), ip_range='2.1.1.1-2.1.1.2', netlink_role='standby')

Then create the multilink specifying the multilink members::

        Multilink.create(name='internet', multilink_members=[member, member1])

.. seealso:: :class:`~Multilink`
"""
from smc.base.model import Element, ElementCreator, ElementCache, ElementRef, ElementList
from smc.base.structs import NestedDict
from smc.vpn.elements import ConnectionType
from smc.base.util import element_resolver
from smc.core.general import RankedDNSAddress
from smc.compat import is_api_version_less_than_or_equal














[docs] class MultilinkMember(object): """ A multilink member represents an netlink member used on a multilink configuration. Multilink uses netlinks to specify settings specific to a connection, network, whether it should be active or standby and optionally QoS. Use this class to create mutlilink members that are required for creating a Multilink element. :ivar Network network: network element reference specifying netlink subnet :ivar StaticNetlink,DynamicNetlink netlink: netlink element reference """ network = ElementRef("network_ref") netlink = ElementRef("netlink_ref") def __init__(self, kwargs): self.data = ElementCache(kwargs) def __eq__(self, other): return all( [ self.ip_range == other.ip_range, self.netlink_role == other.netlink_role, self.data.get("network_ref") == other.data.get("network_ref"), self.data.get("netlink_ref") == other.data.get("netlink_ref"), ] ) def __ne__(self, other): return not self == other def __hash__(self): return hash( ( self.ip_range, self.netlink_role, self.data.get("network_ref"), self.data.get("netlink_ref"), ) ) @property def ip_range(self): """ Specifies the IP address range for dynamic source address translation (NAT) for the internal source IP addresses on the NetLink. Can also be set. :rtype: str """ return self.data.get("ip_range") @ip_range.setter def ip_range(self, value): if "-" in value: self.data.update(ip_range=value) @property def netlink_role(self): """ Shows whether the Netlink is active or standby. Active - traffic is routed through the NetLink according to the method you specify in the Outbound Multi-Link element properties. Standby - traffic is only routed through the netlink if all primary (active) netlinks are unavailable. :rtype: str """ return self.data.get("netlink_role") @netlink_role.setter def netlink_role(self, value): if value in ("standby", "active"): self.data.update(netlink_role=value)
[docs] @classmethod def create(cls, netlink, ip_range=None, netlink_role="active"): """ Create a multilink member. Multilink members are added to an Outbound Multilink configuration and define the ip range, static netlink to use, and the role. This element can be passed to the Multilink constructor to simplify creation of the outbound multilink. :param StaticNetlink,DynamicNetlink netlink: static netlink element to use as member :param str ip_range: the IP range for source NAT for this member. The IP range should be part of the defined network range used by this netlink. Not required for dynamic netlink :param str netlink_role: role of this netlink, 'active' or 'standby' :raises ElementNotFound: Specified netlink could not be found :rtype: MultilinkMember """ member_def = dict( netlink_ref=netlink.href, netlink_role=netlink_role, ip_range=ip_range if netlink.typeof == "netlink" else "0.0.0.0", ) if netlink.typeof == "netlink": # static netlink vs dynamic netlink member_def.update(network_ref=netlink.network[0].href) return cls(member_def)
def __repr__(self): return "MultilinkMember(netlink={},netlink_role={},ip_range={})".format( self.netlink, self.netlink_role, self.ip_range )
[docs] class LinkType(Element): """ This represents the Link Type. """ typeof = "link_type"
[docs] @classmethod def create(cls, name, comment=None): """ Create a new Link Type. :param str name: name of link type :param str comment: comment for link type :raises CreateElementFailed: failed to create link type :rtype: LinkType """ json = {"name": name, "comment": comment} return ElementCreator(cls, json)
[docs] class IpNetLinkWeight(NestedDict): """ Clients make their incoming connections to the address of the Server Pool. The Firewall then decides which server is going to handle the connection and translates (in a NAT operation) the public address to the private IP address of that server. The external address or addresses of the Server Pool are defined as properties of the Server Pool element. """ def __init__(self, data): super(IpNetLinkWeight, self).__init__(data=data)
[docs] @classmethod def create(cls, arp_generate=True, ipaddress=None, netlink=None, network=None, status=True): """ :param bool arp_generate: Automatically generate a proxy ARP for the NATed address in the selected Network. Otherwise, must be defined in the ARP entry manually in the Firewall element properties.Not Required, Default is true. :param str ipaddress: Defines the external NATed destination IP Address for the Server Pool: A valid IPv4 or IPv6 address. This is the address client machines contact when accessing the service that the server(s) in the Server Pool offer. Required :param StaticNetlink netlink: NetLink to use. To configure load sharing for the servers but no traffic balancing between NetLinks, select Not Specified (netlink/0). Required :param Network network: Network element that is used for the Server Pool’s external NATed address. Required :param bool status: Weight of this Net Link in the pool. Set the weight to false to disable the net link. Not Required, Default is true. :rtype: IpNetLinkWeight """ json = { "arp_generate": arp_generate, "ipaddress": ipaddress, "netlink_ref": element_resolver(netlink), "weight": 1 if status else 0 } if not network: json.update(network_ref=netlink.data.get("network_ref")[0]) else: json.update(network_ref=element_resolver(network)) return cls(json)
@property def arp_generate(self): """ Automatically generate a proxy ARP for the NATed address in the selected Network. :rtype: bool """ return self.data.get("arp_generate") @property def ipaddress(self): """ External NATed destination IP Address for the Server Pool :rtype: str """ return self.data.get("ipaddress") @property def netlink_ref(self): """ NetLink to use. :rtype: StaticNetlink """ return Element.from_href(self.data.get("netlink_ref")) @property def weight(self): """ Weight of this Net Link in the pool. :rtype: int """ return self.data.get("weight") @property def network_ref(self): """ Network element that is used for the Server Pool’s external NATed address :rtype: list(Network) """ return [Element.from_href(network) for network in self.data.get("network_ref")]
[docs] class ServerPoolMember(NestedDict): """ Host element for the internal IP address of each member of the Server Pool. The Firewall uses these addresses to select which server handles which traffic that arrives to the Server Pool’s external address. The Server Pool can have any number of members. You can also create a one-server Server Pool to enable DDNS updates for a single server when ISP links go down if the server does not need the other Server Pool features. """
[docs] @classmethod def create(cls, member_rank=None, member=None): """ :param int member_rank: Order of the network element in the list: -1 means no order. Not Required :param NetworkElement member: Existing Server element (for servers that have some special role in the SMC configuration) or Host element (for other servers). Required :rtype: ServerPoolMember """ json = { "member_rank": member_rank, "member": element_resolver(member) } return cls(json)
[docs] class ServerPool(Element): """ This represents a Server Pool. A Network Element representing a group of Servers. Used for inbound traffic management. Clients make their incoming connections to the address of the Server Pool. The Firewall then decides which server is going to handle the connection and translates (in a NAT operation) the public address to the private IP address of that server. The external address or addresses of the Server Pool are defined as properties of the Server Pool element. """ typeof = "server_pool"
[docs] @classmethod def create(cls, name=None, ip_netlink_weight=None, members_list=None, monitoring_frequency=10, monitoring_mode="ping", monitoring_port=0, server_allocation="host", monitoring_request=None, monitoring_response=None, monitoring_url=None, monitoring_host=None, dns_server=None, domain_name=None, comment=None): """ :param str name: The name of server pool. :param list(IpNetLinkWeight) ip_netlink_weight: Clients make their incoming connections to the address of the Server Pool. :param list(ServerPoolMember) members_list: List of Members. :param int monitoring_frequency: How often the availability will checked (seconds). Integer between 0 and 65535 seconds. Required :param str monitoring_mode: Monitoring Method for monitoring the availability of the servers in the Server Pool. Required The available monitoring mode given below: 1. ping: Uses ICMP echo request (ping) messages to monitor the availability of the servers. 2. agent: Uses the Server Pool Monitoring Agent feature. Before enabling this method, make sure you have installed and configured the Monitoring Agents on all the servers See Installing Monitoring Agents. For instructions on how to configure this feature, see Enabling Monitoring Agents. 3. tcp: Checks that a specific TCP service is available. 4. http: Checks that the HTTP service is available. :param int monitoring_port: Define the port number (0 to 65535). Not Required :param str server_allocation: Select the granularity for the server selection (defines how likely it is that traffic is redirected to a particular server). Usually it is best to choose the least granular option that still produces an acceptable distribution of traffic. The options are (from least granular to most granular): 1. order: Allocate traffic by order of priority, when a member is not available the next one in the list is chosen. 2. network: directs traffic coming from the same C-class network to the same server. This is a good choice when connections come from many different networks. 3. host: directs traffic coming from the same IP address to the same server. This is a good choice when a large portion of connections come from different hosts in the same C-class network. 4. connection: makes a new traffic management decision for each new connection. This choice may be necessary if a large portion of connections uses just one IP address. 5. notdefined: has the same effect as the Source Network option. :param str monitoring_request: String of text that to be sent. Not Required :param str monitoring_response: String of text that expected to receive. In HTTP mode: the text can be returned from the HTTP protocol headers or the actual content of the web page. :param str monitoring_url: Define the path to the web page. :param str monitoring_host: Define the host name of the web server. :param DNSServer dns_server: DNSServer Firewalls support the Dynamic DNS protocol and can send DDNS updates to a specified DNS server. If a network connection specified by a NetLink element fails, the dynamic DNS updates notify the DNS, which then removes the corresponding IP address from its records :param str domain_name: Fully Qualified Domain Name. :param str comment: Optional comment. :rtype: ServerPool """ json = { "name": name, "ip_netlink_weight": [ip_netlink.data for ip_netlink in ip_netlink_weight], "members_list": [member.data for member in members_list], "monitoring_frequency": monitoring_frequency, "monitoring_mode": monitoring_mode, "monitoring_port": monitoring_port, "server_allocation": server_allocation, "comment": comment, } if monitoring_request or monitoring_response or monitoring_url or monitoring_host: json.update(monitoring_request=monitoring_request, monitoring_response=monitoring_response, monitoring_url=monitoring_url, monitoring_host=monitoring_host) if dns_server: json.update(dns_server=element_resolver(dns_server), domain_name=domain_name) return ElementCreator(cls, json)
@property def ip_netlink_weight(self): """ The address of the Server Pool :rtype: list(IpNetLinkWeight) """ return [IpNetLinkWeight(netlink) for netlink in self.data.get("ip_netlink_weight")]