[ovs-dev] [PATCH] vtep: support L3 logical router E-W traffic in Hardware vtep emulator

Guru Shetty guru at ovn.org
Mon Dec 7 16:53:43 UTC 2015


On 6 December 2015 at 23:23, Shuangmin Zhang <shuangminz at vmware.com> wrote:

> Signed-off-by: Shuangmin Zhang <shuangminz at vmware.com>
>

How did you send this patch? Are you able to download this mail and apply
it with 'git am'? If not, try sending a mail to yourself with 'git
send-email' and then download that mail (if destination is gmail, you can
do a 'show original' and then download. If you use mutt, you can simply
download) and then 'git am' that saved mail (if gmail, you need to remove
the first line)

To install all the things needed to use 'git send-email' on Ubuntu, you
will need to install the following packages.
sudo apt-get install git git-email libmail-sendmail-perl libmailtools-perl


>
>
> ---
>
>   vtep/ovs-vtep
>
>   vtep/vtep-ctl.c
>
> 2 files changed, 462 insertions(+), 3 deletions(-)
>
>
>
> diff --git a/vtep/ovs-vtep b/vtep/ovs-vtep
>
> index 46a5692..41b3a9b 100755
>
> --- a/vtep/ovs-vtep
>
> +++ b/vtep/ovs-vtep
>
> @@ -43,8 +43,11 @@ ps_name = ""
>
>  ps_type = ""
>
>  Tunnel_Ip = ""
>
>  Lswitches = {}
>
> +Lrouters = {}
>
>  Bindings = {}
>
> +Switch_Bindings = {}
>
>  ls_count = 0
>
> +lr_count = 0
>
>  tun_id = 0
>
>  bfd_bridge = "vtep_bfd"
>
>  bfd_ref = {}
>
> @@ -56,6 +59,7 @@ def call_prog(prog, args_list):
>
>          output = ""
>
>      else:
>
>          output = output[0].strip()
>
> +
>
>      return output
>
>
>
>  def ovs_vsctl(args):
>
> @@ -74,6 +78,227 @@ def unixctl_exit(conn, unused_argv, unused_aux):
>
>      conn.reply(None)
>
>
>
>
>
> +class Logical_Router(object):
>
> +    def __init__(self, lr_name):
>
> +        global lr_count
>
> +        self.name = lr_name
>
> +        #lr_count += 1
>
> +        #self.short_name = "vtep_lr" + str(lr_count)
>
> +        self.short_name = "vtep_" + lr_name
>
> +        vlog.info("creating lrouter %s (%s)" % (self.name,
> self.short_name))
>
> +        self.ports = {}
>
> +        self.dst_ips = {}
>
> +        self.lifs = {}
>
> +        self.setup_lr()
>
> +
>
> +    def __del__(self):
>
> +        vlog.info("destroying lrouter %s" % self.name)
>
> +
>
> +    def setup_lr(self):
>
> +        if ps_type:
>
> +            ovs_vsctl("--may-exist add-br %s -- set Bridge %s
> datapath_type=%s"
>
> +                      % (self.short_name, self.short_name, ps_type))
>
> +        else:
>
> +            ovs_vsctl("--may-exist add-br %s" % self.short_name)
>
> +
>
> +        ovs_vsctl("br-set-external-id %s vtep_logical_router true"
>
> +                  % self.short_name)
>
> +        ovs_vsctl("br-set-external-id %s logical_router_name %s"
>
> +                  % (self.short_name, self.name))
>
> +
>
> +        ovs_ofctl("del-flows %s" % self.short_name)
>
> +        ovs_ofctl("add-flow %s priority=0,action=drop" % self.short_name)
>
> +
>
> +    def update_flood(self):
>
> +        flood_ports = self.ports.values()
>
> +
>
> +        ovs_ofctl("add-flow %s table=1,priority=0,action=%s"
>
> +                  % (self.short_name, ",".join(flood_ports)))
>
> +
>
> +    def run(self):
>
> +        #vlog.info("start lrouter running")
>
> +        self.update_lif_macs()
>
> +        self.update_forwarding_macs()
>
> +
>
> +    def update_lif_macs(self):
>
> +        lif_pl_uuid = vtep_ctl("--columns=_uuid find Physical_Locator
> dst_ip=127.0.0.1").partition(":")[2].strip()
>
> +        new_lifs = set()
>
> +
>
> +        # update lif macs
>
> +        for switch_binding in Switch_Bindings.keys():
>
> +            lr_name, lif = switch_binding.split("-", 1)
>
> +            if lr_name != self.name:
>
> +                continue
>
> +
>
> +            ls_name = Switch_Bindings[switch_binding]
>
> +            ls_uuid = get_logical_switch_uuid(ls_name)
>
> +            lif_mac_column = vtep_ctl("--columns=MAC find
> Ucast_Macs_Remote logical_switch=%s locator=%s"
>
> +                                      % (ls_uuid, lif_pl_uuid))
>
> +
>
> +            if not lif_mac_column:
>
> +                continue
>
> +
>
> +            lif_ip = lif.strip("\"").partition("(")[2].partition("/")[0]
>
> +            lif_ip_mask = lif.strip("\"").partition("(")[2].strip(")")
>
> +            lif_port_r = lif.strip("\"").partition("(")[0].strip() + "-r"
>
> +            lif_mac = lif_mac_column.partition(":")[2].strip()
>
> +
>
> +            new_lifs.add(lif)
>
> +            if lif in self.lifs.keys():
>
> +                if self.lifs[lif] == lif_mac:
>
> +                    continue
>
> +                else:
>
> +                    del self.lifs[lif]
>
> +                    ovs_ofctl("del-flow %s ip,nw_dst=%s" %
> (self.short_name, lif_ip_mask))
>
> +
>
> +            self.lifs[lif] = lif_mac
>
> +
>
> +            # get ip's hex format
>
> +            lif_ip_hex = getHexIp(lif_ip)
>
> +            lif_mac_hex = "0x" + "".join(lif_mac.strip("\"").split(":"))
>
> +
>
> +            # create ARP flow table
>
> +            ovs_ofctl("add-flow %s
> table=1,dl_type=0x0806,nw_dst=%s,actions="
>
> +
> "move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:%s,"
>
> +
> "load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],"
>
> +                      "move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],"
>
> +                      "load:%s->NXM_NX_ARP_SHA[],"
>
> +                      "load:%s->NXM_OF_ARP_SPA[],in_port"
>
> +                      % (self.short_name, lif_ip, lif_mac, lif_mac_hex,
> lif_ip_hex))
>
> +
>
> +            # don't flood arp request from same subnet (except gateway)
> to other lif
>
> +            ovs_ofctl("add-flow %s
> table=1,priority=1,in_port=%s,dl_type=0x0806,nw_dst=%s,action=drop"
>
> +                      % (self.short_name, self.ports[lif_port_r],
> lif_ip_mask))
>
> +
>
> +            ovs_ofctl("add-flow %s
> table=2,priority=1,dl_type=0x0800,nw_dst=%s,action=mod_dl_src=%s,dec_ttl,resubmit(,3)"
>
> +                      % (self.short_name, lif_ip_mask, lif_mac))
>
> +
>
> +        dead_lifs = set(self.lifs.keys()).difference(new_lifs)
>
> +        for lif in dead_lifs:
>
> +            del self.lifs[lif]
>
> +            lif_ip_mask = lif.strip("\"").partition("(")[2].strip(")")
>
> +            ovs_ofctl("del-flow %s ip,nw_dst=%s" % (self.short_name,
> lif_ip_mask))
>
> +
>
> +    def update_forwarding_macs(self):
>
> +        # update lif macs
>
> +        lif_pl_uuid = vtep_ctl("--columns=_uuid find Physical_Locator
> dst_ip=127.0.0.1").partition(":")[2].strip()
>
> +
>
> +        new_dst_ips = set()
>
> +        for switch_binding in Switch_Bindings.keys():
>
> +            lr_name, lif = switch_binding.split("-", 1)
>
> +            if lr_name != self.name:
>
> +                continue
>
> +
>
> +            ls_name = Switch_Bindings[switch_binding]
>
> +            ls_uuid = get_logical_switch_uuid(ls_name)
>
> +            lif_port = lif.strip("\"").partition("(")[0].strip() + "-r"
>
> +
>
> +            new_dst_ips = new_dst_ips |
> self.update_forward_macs_by_table(ls_uuid, lif_pl_uuid, "Ucast_Macs_Local",
> lif_port)
>
> +            new_dst_ips = new_dst_ips |
> self.update_forward_macs_by_table(ls_uuid, lif_pl_uuid,
> "Ucast_Macs_Remote", lif_port)
>
> +
>
> +        dead_ips = set(self.dst_ips.keys()).difference(new_dst_ips)
>
> +        for ip in dead_ips:
>
> +            ovs_ofctl("del-flows %s ip,nw_dst=%s" % (self.short_name, ip))
>
> +            ovs_ofctl("del-flows %s dl_dst=%s" % (self.short_name,
> self.dst_ips[ip]))
>
> +            del self.dst_ips[ip]
>
> +
>
> +
>
> +    def update_forward_macs_by_table(self, ls_uuid, lif_pl_uuid, table,
> lif_port):
>
> +        columns = vtep_ctl("--columns=locator find %s logical_switch=%s"
> % (table, ls_uuid)).splitlines()
>
> +        new_dst_ips = set()
>
> +
>
> +        for column in columns:
>
> +            if not column:
>
> +                continue
>
> +
>
> +            pl_uuid = column.partition(":")[2].strip()
>
> +            if pl_uuid == lif_pl_uuid:
>
> +                continue
>
> +
>
> +            ipaddr_lines = vtep_ctl("--columns=ipaddr find %s
> logical_switch=%s locator=%s" % (table, ls_uuid, pl_uuid)).splitlines()
>
> +            for ipaddr_line in ipaddr_lines:
>
> +                ipaddr = ipaddr_line.partition(":")[2].strip()
>
> +                if not ipaddr:
>
> +                    continue
>
> +
>
> +                dst_ip = ipaddr.strip("\"").partition("(")[2].strip(")")
>
> +                new_dst_ips.add(dst_ip)
>
> +
>
> +                # get destination's mac address from table
>
> +                column = vtep_ctl("--columns=MAC find %s
> logical_switch=%s ipaddr=%s"
>
> +                                  % (table, ls_uuid, ipaddr))
>
> +                dst_mac = column.partition(":")[2].strip()
>
> +
>
> +                if dst_ip in self.dst_ips.keys():
>
> +                    if self.dst_ips[dst_ip] == dst_mac:
>
> +                        continue
>
> +                    else:
>
> +                        ovs_ofctl("del-flows %s ip,nw_dst=%s" %
> (self.short_name, dst_ip))
>
> +                        ovs_ofctl("del-flows %s dl_dst=%s" %
> (self.short_name, self.dst_ips[dst_ip]))
>
> +                        del self.dst_ips[dst_ip]
>
> +
>
> +                self.dst_ips[dst_ip] = dst_mac
>
> +                ovs_ofctl("add-flow %s
> table=3,priority=1000,dl_type=0x0800,nw_dst=%s,action=mod_dl_dst:%s,dec_ttl,output:%s"
>
> +                          % (self.short_name, dst_ip, dst_mac,
> self.ports[lif_port]))
>
> +
>
> +        return new_dst_ips
>
> +
>
> +    # binding logical switch's LIF with local router which
>
> +    def add_switch_binding(self, binding, ls):
>
> +        vlog.info("adding switch binding %s" % binding)
>
> +
>
> +        lr_name, lif = binding.split("-", 1)
>
> +        lif_port = lif.strip("\"").partition("(")[0].strip()
>
> +        lif_port_r = lif_port+"-r"
>
> +        lif_port_s = lif_port+"-s"
>
> +
>
> +        lif_ip = lif.strip("\"").partition("(")[2].partition("/")[0]
>
> +        lif_ip_mask = lif.strip("\"").partition("(")[2].strip(")")
>
> +
>
> +        #Create a patch port that connects the Logical Switch to the
> Logical Router
>
> +        ovs_vsctl("add-port %s %s "
>
> +                  " -- set Interface %s type=patch options:peer=%s"
>
> +                  % (ls.short_name, lif_port_s, lif_port_s, lif_port_r))
>
> +        ovs_vsctl("add-port %s %s "
>
> +                  " -- set Interface %s type=patch options:peer=%s"
>
> +                  % (self.short_name, lif_port_r, lif_port_r, lif_port_s))
>
> +
>
> +        port_s_no = ovs_vsctl("get Interface %s ofport" % lif_port_s)
>
> +        port_r_no = ovs_vsctl("get Interface %s ofport" % lif_port_r)
>
> +
>
> +        # create flow to switch to arp table whenever it is arp packet
>
> +        #ovs_ofctl("add-flow %s
> table=0,priority=1000,dl_type=0x0806,actions=resubmit(,1)" %
> self.short_name)
>
> +
>
> +        # create flow to switch to routing table for other packets
>
> +        ovs_ofctl("add-flow %s table=0,priority=1,actions=resubmit(,2)" %
> self.short_name)
>
> +
>
> +        ls.add_lbinding(lif_port_s)
>
> +        self.add_lbinding(lif_port_r)
>
> +
>
> +    def add_lbinding(self, lbinding):
>
> +        vlog.info("adding %s binding to %s" % (lbinding, self.name))
>
> +        port_no = ovs_vsctl("get Interface %s ofport" % lbinding)
>
> +        self.ports[lbinding] = port_no
>
> +        ovs_ofctl("add-flow %s dl_type=0x0806,action=learn(table=1,"
>
> +        #          "priority=1000,idle_timeout=15,cookie=0x5000,"
>
> +                  "priority=1000,cookie=0x5000,"
>
> +                  "NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],"
>
> +                  "output:NXM_OF_IN_PORT[]),resubmit(,1)"
>
> +                  % (self.short_name))
>
> +
>
> +        self.update_flood()
>
> +
>
> +    def del_lbinding(self, lbinding, lif):
>
> +        vlog.info("removing %s binding from %s" % (lbinding, self.name))
>
> +        port_no = self.ports[lbinding]
>
> +        ovs_ofctl("del-flows %s in_port=%s" % (self.short_name, port_no));
>
> +        del self.ports[lbinding]
>
> +        self.update_flood()
>
> +
>
> +        lif_ip_mask = lif.strip("\"").partition("(")[2].strip(")")
>
> +        ovs_ofctl("del-flows %s ip,nw_dst=%s" % (self.short_name,
> lif_ip_mask));
>
> +        ovs_ofctl("del-flows %s arp,arp_tpa=%s" % (self.short_name,
> lif_ip_mask));
>
> +
>
>  class Logical_Switch(object):
>
>      def __init__(self, ls_name):
>
>          global ls_count
>
> @@ -87,6 +312,7 @@ class Logical_Switch(object):
>
>          self.remote_macs = {}
>
>          self.unknown_dsts = set()
>
>          self.tunnel_key = 0
>
> +        self.logical_router = None
>
>          self.setup_ls()
>
>
>
>      def __del__(self):
>
> @@ -115,7 +341,9 @@ class Logical_Switch(object):
>
>          ovs_vsctl("br-set-external-id %s logical_switch_name %s"
>
>                    % (self.short_name, self.name))
>
>
>
> -        vtep_ctl("clear-local-macs %s" % self.name)
>
> +        # since so far L3 local/remote macs are persisted in DB instead
> of querying by arp request, so keep from clean for now.
>
> +        # will remove this limiation when arp resolution issue is solved
>
> +        #vtep_ctl("clear-local-macs %s" % self.name)
>
>          vtep_ctl("add-mcast-local %s unknown-dst %s" % (self.name,
> Tunnel_Ip))
>
>
>
>          ovs_ofctl("del-flows %s" % self.short_name)
>
> @@ -260,6 +488,9 @@ class Logical_Switch(object):
>
>                  continue
>
>
>
>              if parse_ucast:
>
> +                # exclude gateway's tunnel which has no meaning
>
> +                if entry[2].find("127.0.0.1") != -1:
>
> +                    continue
>
>                  remote_macs[entry[1]] = entry[2]
>
>              else:
>
>                  if entry[1] != "unknown-dst":
>
> @@ -475,6 +706,16 @@ def run_bfd():
>
>                    bfd_lconf_default['bfd_config_local:bfd_dst_mac'],
>
>                    bfd_dst_mac))
>
>
>
> +def getHexIp(ip):
>
> +    hexip ="0x"
>
> +    for i in ip.split('.'):
>
> +        if int(i) < 16:
>
> +            hexip += "0"+ hex(int(i))[2:]
>
> +        else:
>
> +            hexip += hex(int(i))[2:]
>
> +
>
> +    return hexip
>
> +
>
>  def add_binding(binding, ls):
>
>      vlog.info("adding binding %s" % binding)
>
>
>
> @@ -516,6 +757,23 @@ def add_binding(binding, ls):
>
>      ls.add_lbinding(lbinding)
>
>      Bindings[binding] = ls.name
>
>
>
> +def del_switch_binding(binding, ls):
>
> +    vlog.info("removing switch binding %s" % binding)
>
> +
>
> +    lr_name, lif = binding.split("-", 1)
>
> +    lif_port_r = lif.strip("\"").partition("(")[0].strip() + "-r"
>
> +    lif_port_s = lif.strip("\"").partition("(")[0].strip() + "-s"
>
> +
>
> +    lr = Lrouters[lr_name]
>
> +    lr.del_lbinding(lif_port_r, lif)
>
> +    ls.del_lbinding(lif_port_s)
>
> +
>
> +    # Destroy the patch port that connects the lrouter to the lswitch
>
> +    ovs_vsctl("del-port %s %s -- del-port %s %s"
>
> +              % (lr.short_name, lif_port_r, ls.short_name, lif_port_s))
>
> +
>
> +    del Switch_Bindings[binding]
>
> +
>
>  def del_binding(binding, ls):
>
>      vlog.info("removing binding %s" % binding)
>
>
>
> @@ -545,6 +803,38 @@ def del_binding(binding, ls):
>
>
>
>      del Bindings[binding]
>
>
>
> +def get_logical_switch_uuid(ls_name):
>
> +    column = vtep_ctl("--columns=_uuid find Logical_Switch "
>
> +                      "name=%s" % ls_name)
>
> +    return column.partition(":")[2].strip()
>
> +
>
> +def get_switch_bindings():
>
> +    # get the total list of switch bindings from all routers
>
> +    New_Switch_Bindings = {}
>
> +    binding_lines = set(vtep_ctl("--columns=switch_binding find
> Logical_Router").splitlines())
>
> +    for line in binding_lines:
>
> +        binding_line = line.partition(":")[2].strip().strip("{}")
>
> +        if not binding_line:
>
> +            continue
>
> +
>
> +        bindings = binding_line.split(",")
>
> +
>
> +        # get lr name
>
> +        column = vtep_ctl("--columns=name find Logical_Router "
>
> +                          "switch_binding=\'%s\'" % binding_line)
>
> +        lr_name = column.partition(":")[2].strip()
>
> +
>
> +        for binding in bindings:
>
> +            lif, ls_uuid = binding.split("=", 1)
>
> +            switch_binding = lr_name + "-" + lif.strip()
>
> +            if New_Switch_Bindings.has_key(switch_binding):
>
> +                ovs.util.ovs_fatal(0, "find duplicate lr-lif bindings
> (%s-%s)" % (lr_name, lif), vlog)
>
> +
>
> +            ls_name = vtep_ctl("get Logical_Switch %s name" %
> ls_uuid).strip("\"")
>
> +            New_Switch_Bindings[switch_binding] = ls_name
>
> +
>
> +    return New_Switch_Bindings
>
> +
>
>  def handle_physical():
>
>      # Gather physical ports except the patch ports we created
>
>      ovs_ports = ovs_vsctl("list-ports %s" % ps_name).split()
>
> @@ -568,6 +858,7 @@ def handle_physical():
>
>          for b in binding_set:
>
>              vlan, ls_name = b.split()
>
>              if ls_name not in Lswitches:
>
> +                vlog.info("add ls %s" % (ls_name))
>
>                  Lswitches[ls_name] = Logical_Switch(ls_name)
>
>
>
>              binding = "%s-%s" % (vlan, pp_name)
>
> @@ -582,7 +873,6 @@ def handle_physical():
>
>
>
>              add_binding(binding, ls)
>
>
>
> -
>
>      dead_bindings = set(Bindings.keys()).difference(new_bindings)
>
>      for binding in dead_bindings:
>
>          ls_name = Bindings[binding]
>
> @@ -596,6 +886,52 @@ def handle_physical():
>
>              vtep_ctl("clear-local-macs %s" % Lswitches[ls_name].name)
>
>              del Lswitches[ls_name]
>
>
>
> +    # update logical router
>
> +    new_switch_bindings = get_switch_bindings()
>
> +    for b in new_switch_bindings:
>
> +        lr_name, lif = b.split("-",1)
>
> +        ls_name = new_switch_bindings[b]
>
> +
>
> +        if lr_name not in Lrouters:
>
> +            vlog.info("add lr %s " % (lr_name))
>
> +            Lrouters[lr_name] = Logical_Router(lr_name)
>
> +
>
> +        if ls_name not in Lswitches:
>
> +            vlog.info("add ls %s " % (ls_name))
>
> +            Lswitches[ls_name] = Logical_Switch(ls_name)
>
> +
>
> +        lr = Lrouters[lr_name]
>
> +        ls = Lswitches[ls_name]
>
> +
>
> +        if Switch_Bindings.has_key(b):
>
> +            if Switch_Bindings[b] == ls_name:
>
> +                continue
>
> +            else:
>
> +                del_switch_binding(switch_binding,
> Lswitches[Switch_Bindings[b]])
>
> +
>
> +        Switch_Bindings[b] = ls_name
>
> +        lr.add_switch_binding(b, ls)
>
> +
>
> +    dead_bindings =
> set(Switch_Bindings.keys()).difference(new_switch_bindings.keys())
>
> +    for binding in dead_bindings:
>
> +        lr_name, lif = binding.split("-",1)
>
> +        ls_name = Switch_Bindings[binding]
>
> +
>
> +        ls = Lswitches[ls_name]
>
> +        del_switch_binding(binding, ls)
>
> +
>
> +        if not len(ls.ports):
>
> +            ls.cleanup_ls()
>
> +            ovs_vsctl("del-br %s" % Lswitches[ls_name].short_name)
>
> +            vtep_ctl("clear-local-macs %s" % Lswitches[ls_name].name)
>
> +            del Lswitches[ls_name]
>
> +
>
> +        lr = Lrouters[lr_name]
>
> +        if not len(lr.ports):
>
> +            ovs_vsctl("del-br %s" % lr.short_name)
>
> +            vtep_ctl("clear-local-macs %s" % lr.name)
>
> +            del Lrouters[lr_name]
>
> +
>
>  def setup():
>
>      br_list = ovs_vsctl("list-br").split()
>
>      if (ps_name not in br_list):
>
> @@ -695,6 +1031,9 @@ def main():
>
>          for ls_name, ls in Lswitches.items():
>
>              ls.run()
>
>
>
> +        for lr_name, lr in Lrouters.items():
>
> +            lr.run()
>
> +
>
>          run_bfd()
>
>
>
>          poller = ovs.poller.Poller()
>
> diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c
>
> index 604d19d..25e9bec 100644
>
> --- a/vtep/vtep-ctl.c
>
> +++ b/vtep/vtep-ctl.c
>
> @@ -88,6 +88,10 @@ static struct vtep_ctl_lswitch *find_lswitch(struct
> vtep_ctl_context *,
>
>                                               const char *name,
>
>                                               bool must_exist);
>
>
>
> +static struct vtep_ctl_lrouter *find_lrouter(struct vtep_ctl_context *,
>
> +                                             const char *name,
>
> +                                             bool must_exist);
>
> +
>
>  int
>
>  main(int argc, char *argv[])
>
>  {
>
> @@ -437,6 +441,8 @@ struct vtep_ctl_context {
>
>                               * struct vtep_ctl_lswitch. */
>
>      struct shash plocs;     /* Maps from "<encap>+<dst_ip>" to
>
>                               * struct vteprec_physical_locator. */
>
> +    struct shash lrouters; /* Maps from logical router name to
>
> +                             * struct vtep_ctl_lswitch. */
>
>  };
>
>
>
>  /* Casts 'base' into 'struct vtep_ctl_context'. */
>
> @@ -468,6 +474,15 @@ struct vtep_ctl_lswitch {
>
>      struct shash mcast_remote;  /* Maps from mac to vtep_ctl_mcast_mac. */
>
>  };
>
>
>
> +struct vtep_ctl_lrouter {
>
> +    const struct vteprec_logical_router *lr_cfg;
>
> +    char *name;
>
> +    struct shash ucast_local;   /* Maps from mac to
> vteprec_ucast_macs_local. */
>
> +    struct shash ucast_remote;  /* Maps from mac to
> vteprec_ucast_macs_remote.*/
>
> +    struct shash mcast_local;   /* Maps from mac to vtep_ctl_mcast_mac. */
>
> +    struct shash mcast_remote;  /* Maps from mac to vtep_ctl_mcast_mac. */
>
> +};
>
> +
>
>  struct vtep_ctl_mcast_mac {
>
>      const struct vteprec_mcast_macs_local *local_cfg;
>
>      const struct vteprec_mcast_macs_remote *remote_cfg;
>
> @@ -597,6 +612,32 @@ del_cached_lswitch(struct vtep_ctl_context *ctx,
> struct vtep_ctl_lswitch *ls)
>
>      free(ls);
>
>  }
>
>
>
> +static struct vtep_ctl_lrouter *
>
> +add_lrouter_to_cache(struct vtep_ctl_context *vtepctl_ctx,
>
> +                     const struct vteprec_logical_router *lr_cfg)
>
> +{
>
> +    struct vtep_ctl_lrouter *lr = xmalloc(sizeof *lr);
>
> +    lr->lr_cfg = lr_cfg;
>
> +    lr->name = xstrdup(lr_cfg->name);
>
> +    shash_add(&vtepctl_ctx->lrouters, lr->name, lr);
>
> +    shash_init(&lr->ucast_local);
>
> +    shash_init(&lr->ucast_remote);
>
> +    shash_init(&lr->mcast_local);
>
> +    shash_init(&lr->mcast_remote);
>
> +    return lr;
>
> +}
>
> +
>
> +static void
>
> +del_cached_lrouter(struct vtep_ctl_context *ctx, struct vtep_ctl_lrouter
> *lr)
>
> +{
>
> +    if (lr->lr_cfg) {
>
> +        vteprec_logical_router_delete(lr->lr_cfg);
>
> +    }
>
> +    shash_find_and_delete(&ctx->lrouters, lr->name);
>
> +    free(lr->name);
>
> +    free(lr);
>
> +}
>
> +
>
>  static void
>
>  commit_ls_bindings(struct vtep_ctl_port *port)
>
>  {
>
> @@ -848,12 +889,13 @@ vtep_ctl_context_populate_cache(struct ctl_context
> *ctx)
>
>      struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx);
>
>      const struct vteprec_global *vtep_global = vtepctl_ctx->vtep_global;
>
>      const struct vteprec_logical_switch *ls_cfg;
>
> +    const struct vteprec_logical_router *lr_cfg;
>
>      const struct vteprec_ucast_macs_local *ucast_local_cfg;
>
>      const struct vteprec_ucast_macs_remote *ucast_remote_cfg;
>
>      const struct vteprec_mcast_macs_local *mcast_local_cfg;
>
>      const struct vteprec_mcast_macs_remote *mcast_remote_cfg;
>
>      const struct vteprec_tunnel *tunnel_cfg;
>
> -    struct sset pswitches, ports, lswitches;
>
> +    struct sset pswitches, ports, lswitches, lrouters;
>
>      size_t i;
>
>
>
>      if (vtepctl_ctx->cache_valid) {
>
> @@ -865,6 +907,7 @@ vtep_ctl_context_populate_cache(struct ctl_context
> *ctx)
>
>      shash_init(&vtepctl_ctx->ports);
>
>      shash_init(&vtepctl_ctx->lswitches);
>
>      shash_init(&vtepctl_ctx->plocs);
>
> +    shash_init(&vtepctl_ctx->lrouters);
>
>
>
>      sset_init(&pswitches);
>
>      sset_init(&ports);
>
> @@ -892,6 +935,7 @@ vtep_ctl_context_populate_cache(struct ctl_context
> *ctx)
>
>      sset_destroy(&ports);
>
>
>
>      sset_init(&lswitches);
>
> +    sset_init(&lrouters);
>
>      VTEPREC_LOGICAL_SWITCH_FOR_EACH (ls_cfg, ctx->idl) {
>
>          if (!sset_add(&lswitches, ls_cfg->name)) {
>
>              VLOG_WARN("%s: database contains duplicate logical switch
> name",
>
> @@ -902,6 +946,16 @@ vtep_ctl_context_populate_cache(struct ctl_context
> *ctx)
>
>      }
>
>      sset_destroy(&lswitches);
>
>
>
> +    VTEPREC_LOGICAL_ROUTER_FOR_EACH (lr_cfg, ctx->idl) {
>
> +        if (!sset_add(&lrouters, lr_cfg->name)) {
>
> +            VLOG_WARN("%s: database contains duplicate logical router
> name",
>
> +                      lr_cfg->name);
>
> +            continue;
>
> +        }
>
> +        add_lrouter_to_cache(vtepctl_ctx, lr_cfg);
>
> +    }
>
> +    sset_destroy(&lrouters);
>
> +
>
>      VTEPREC_UCAST_MACS_LOCAL_FOR_EACH (ucast_local_cfg, ctx->idl) {
>
>          struct vtep_ctl_lswitch *ls;
>
>
>
> @@ -1463,6 +1517,64 @@ cmd_unbind_ls(struct ctl_context *ctx)
>
>      vtep_ctl_context_invalidate_cache(ctx);
>
>  }
>
>
>
> +static struct vtep_ctl_lrouter *
>
> +find_lrouter(struct vtep_ctl_context *vtepctl_ctx,
>
> +             const char *name, bool must_exist)
>
> +{
>
> +    struct vtep_ctl_lrouter *lr;
>
> +
>
> +    ovs_assert(vtepctl_ctx->cache_valid);
>
> +
>
> +    lr = shash_find_data(&vtepctl_ctx->lrouters, name);
>
> +    if (must_exist && !lr) {
>
> +        ctl_fatal("no logical router named %s", name);
>
> +    }
>
> +    return lr;
>
> +}
>
> +
>
> +static void
>
> +cmd_add_lr(struct ctl_context *ctx)
>
> +{
>
> +    struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx);
>
> +    const char *lr_name = ctx->argv[1];
>
> +    bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
>
> +    struct vteprec_logical_router *lr;
>
> +
>
> +    vtep_ctl_context_populate_cache(ctx);
>
> +    if (find_lrouter(vtepctl_ctx, lr_name, false)) {
>
> +        if (!may_exist) {
>
> +            ctl_fatal("cannot create logical switch %s because it "
>
> +                      "already exists", lr_name);
>
> +        }
>
> +        return;
>
> +    }
>
> +
>
> +    lr = vteprec_logical_router_insert(ctx->txn);
>
> +    vteprec_logical_router_set_name(lr, lr_name);
>
> +
>
> +    vtep_ctl_context_invalidate_cache(ctx);
>
> +}
>
> +
>
> +static void
>
> +del_lrouter(struct vtep_ctl_context *vtepctl_ctx, struct vtep_ctl_lrouter
> *lr)
>
> +{
>
> +    del_cached_lrouter(vtepctl_ctx, lr);
>
> +}
>
> +
>
> +static void
>
> +cmd_del_lr(struct ctl_context *ctx)
>
> +{
>
> +    struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx);
>
> +    bool must_exist = !shash_find(&ctx->options, "--if-exists");
>
> +    struct vtep_ctl_lrouter *lr;
>
> +
>
> +    vtep_ctl_context_populate_cache(ctx);
>
> +    lr = find_lrouter(vtepctl_ctx, ctx->argv[1], must_exist);
>
> +    if (lr) {
>
> +        del_lrouter(vtepctl_ctx, lr);
>
> +    }
>
> +}
>
> +
>
>  static void
>
>  add_ucast_entry(struct ctl_context *ctx, bool local)
>
>  {
>
> @@ -2044,6 +2156,10 @@ static const struct ctl_table_class tables[] = {
>
>       {{NULL, NULL, NULL},
>
>        {NULL, NULL, NULL}}},
>
>
>
> +    {&vteprec_table_logical_router,
>
> +     {{&vteprec_table_logical_router, &vteprec_logical_router_col_name,
> NULL},
>
> +      {NULL, NULL, NULL}}},
>
> +
>
>      {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
>
>  };
>
>
>
> @@ -2300,6 +2416,10 @@ static const struct ctl_command_syntax
> vtep_commands[] = {
>
>      {"bind-ls", 4, 4, NULL, pre_get_info, cmd_bind_ls, NULL, "", RO},
>
>      {"unbind-ls", 3, 3, NULL, pre_get_info, cmd_unbind_ls, NULL, "", RO},
>
>
>
> +    /* Logical Router commands. */
>
> +    {"add-lr", 1, 1, NULL, pre_get_info, cmd_add_lr, NULL, "--may-exist",
> RW},
>
> +    {"del-lr", 1, 1, NULL, pre_get_info, cmd_del_lr, NULL, "--if-exists",
> RW},
>
> +
>
>      /* MAC binding commands. */
>
>      {"add-ucast-local", 3, 4, NULL, pre_get_info, cmd_add_ucast_local,
> NULL,
>
>       "", RW},
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>



More information about the dev mailing list