Signed-off-by: Shuangmin Zhang <shuangm...@vmware.com>

---

  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@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to