For each lport, adds a priority 90 lflow in ls_in_port_sec and ls_out_port_sec
stages to allow ipv6 traffic for
 - known ipv6 addresses
 - link local address of the lport
 - ip6 packet with ip6.src = :: and ip6.dst=ff02::/64 to allow
   ND packets.

Signed-off-by: Numan Siddique <[email protected]>
---
 lib/packets.h               | 16 ++++++++++++++++
 ovn/northd/ovn-northd.8.xml | 10 ++++++----
 ovn/northd/ovn-northd.c     | 46 ++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 63 insertions(+), 9 deletions(-)

diff --git a/lib/packets.h b/lib/packets.h
index 31a4e92..7c28dfa 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -978,6 +978,22 @@ in6_addr_solicited_node(struct in6_addr *addr, const 
struct in6_addr *ip6)
     memcpy(&addr->s6_addr[13], &ip6->s6_addr[13], 3);
 }
 
+/*
+ * Generates ipv6 link local address from the given eth addr
+ * with prefix 'fe80::/64' and stores it in 'lla'
+ */
+static inline void
+in6_generate_lla(struct eth_addr ea, struct in6_addr *lla)
+{
+    union ovs_16aligned_in6_addr *taddr = (void *) lla;
+    memset(taddr->be16, 0, sizeof(taddr->be16));
+    taddr->be16[0] = htons(0xfe80);
+    taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]);
+    taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff);
+    taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]);
+    taddr->be16[7] = ea.be16[2];
+}
+
 static inline void
 ipv6_multicast_to_ethernet(struct eth_addr *eth, const struct in6_addr *ip6)
 {
diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml
index 376356e..45e9237 100644
--- a/ovn/northd/ovn-northd.8.xml
+++ b/ovn/northd/ovn-northd.8.xml
@@ -154,8 +154,9 @@
           </li>
 
           <li>
-            Priority 90 flow is added to allow all ipv6 traffic if it has
-            ipv6 address(es).
+            Priority 90 flow is added to allow ipv6 traffic if it has
+            ipv6 address(es) which match the <code>inport</code>, valid
+            <code>eth.src</code> and valid <code>ip6.src</code> address(es).
           </li>
 
           <li>
@@ -321,8 +322,9 @@ output;
     <p>
       This is similar to the ingress port security logic in ingress table 0,
       but with important differences.  Most obviously, <code>outport</code> and
-      <code>eth.dst</code> and <code>ip4.dst</code> are checked instead of
-      <code>inport</code>, <code>eth.src</code>, and <code>ip4.src</code>.
+      <code>eth.dst</code>, <code>ip4.dst</code> and <code>ip6.dst</code>are
+      checked instead of <code>inport</code>, <code>eth.src</code>,
+      <code>ip4.src</code> and <code>ip6.src</code>.
       Second, packets directed to broadcast or multicast <code>eth.dst</code>
       are always accepted instead of being subject to the port security rules;
       this is implemented through a priority-100 flow that matches on
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index b10b2e3..1201b78 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -1031,6 +1031,43 @@ build_port_security_ipv4_flow(enum ovn_pipeline 
pipeline, struct ds *match,
     ds_put_cstr(match, ")");
 }
 
+static void
+build_port_security_ipv6_flow(enum ovn_pipeline pipeline, struct ds *match,
+                              struct eth_addr ea, struct in6_addr *ipv6_addrs,
+                              int n_ipv6_addrs)
+{
+    char *ip6_addr_field;
+    if (pipeline == P_IN) {
+        ip6_addr_field = "ip6.src";
+    }
+    else {
+        ip6_addr_field = "ip6.dst";
+    }
+
+    char ip6_str[INET6_ADDRSTRLEN + 1];
+    /* Allow link local address */
+    struct in6_addr lla;
+    in6_generate_lla(ea, &lla);
+    memset(ip6_str, 0, sizeof(ip6_str));
+    ipv6_string_mapped(ip6_str, &lla);
+    ds_put_format(match, " && ip6 && (%s == %s", ip6_addr_field, ip6_str);
+
+    /* Allow ip6.src=:: and ip6.dst=ff02::/64 for ND packets */
+    memset(ip6_str, 0, sizeof(ip6_str));
+    struct in6_addr zero_in6_addr;
+    memset(&zero_in6_addr, 0, sizeof(struct in6_addr));
+    ipv6_string_mapped(ip6_str, &zero_in6_addr);
+
+    ds_put_format(match, " || (ip6.src == %s && ip6.dst == ff02::/64)",
+                  ip6_str);
+    for(int i = 0; i < n_ipv6_addrs; i++) {
+        memset(ip6_str, 0, sizeof(ip6_str));
+        ipv6_string_mapped(ip6_str, &ipv6_addrs[i]);
+        ds_put_format(match, " || %s == %s", ip6_addr_field, ip6_str);
+    }
+    ds_put_cstr(match, ")");
+}
+
 /*
  * Build port security constraints on L2 and L3 address fields and add
  * logical flows to S_SWITCH_(IN/OUT)_PORT_SEC stage.
@@ -1042,8 +1079,7 @@ build_port_security_ipv4_flow(enum ovn_pipeline pipeline, 
struct ds *match,
  *      known ipv4 addresses.
  *    - Add a priority 90 flow to allow ipv4 packets for known ipv4 addresses
  *    - Add a priority 80 flow to drop arp (for ingress) and ip packets
- *    - Add a priority 90 flow to allow all ipv6 packets if port security
- *      has ipv6 address(es).
+ *    - Add a priority 90 flow to allow ipv6 packets for known ipv6 addresses
  *    - Add a priority 80 flow to drop ipv6 packets.
  *    - Add a priority 50 flow to allow all other traffic with the matching
  *      ethernet address.
@@ -1141,12 +1177,12 @@ build_port_security(enum ovn_pipeline pipeline, struct 
ovn_port *op,
         ds_destroy(&match);
 
         if (ps->n_ipv6_addrs) {
-            /* XXX Need to add port security flows for ipv6.
-             * For now add a priority 90 flow to allow all ipv6 traffic */
             ds_init(&match);
-            ds_put_format(&match, "%s == %s && %s == "ETH_ADDR_FMT" && ip6",
+            ds_put_format(&match, "%s == %s && %s == "ETH_ADDR_FMT,
                           port_direction, op->json_key, eth_addr_field,
                           ETH_ADDR_ARGS(ps->ea));
+            build_port_security_ipv6_flow(pipeline, &match, ps->ea,
+                                          ps->ipv6_addrs, ps->n_ipv6_addrs);
             ovn_lflow_add(lflows, op->od, stage, 90, ds_cstr(&match), action);
             ds_destroy(&match);
             free(ps->ipv6_addrs);
-- 
2.5.0

_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev

Reply via email to