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=ff00::/8

Signed-off-by: Numan Siddique <nusid...@redhat.com>
---
 lib/packets.h           | 16 ++++++++++++++++
 ovn/northd/ovn-northd.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 57 insertions(+), 5 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.c b/ovn/northd/ovn-northd.c
index ca7e02e..7003f10 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -1048,6 +1048,42 @@ 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 ipv6_netaddr *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=ff00::/8 for ND packets */
+    if (pipeline == P_IN) {
+        ds_put_cstr(match, " || ip6.src == ::");
+    }
+    else {
+        ds_put_cstr(match, " || ip6.dst == ff00::/8");
+    }
+    for(int i = 0; i < n_ipv6_addrs; i++) {
+        memset(ip6_str, 0, sizeof(ip6_str));
+        ipv6_string_mapped(ip6_str, &ipv6_addrs[i].addr);
+        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.
@@ -1059,8 +1095,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.
@@ -1158,12 +1193,13 @@ 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 */
+            /* XXX Need to add port security flows for ipv6 ND */
             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
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to