diff --git a/controllers/gateway/config_resolver.go b/controllers/gateway/config_resolver.go
index c706e6e8c9..ea7da57b23 100644
--- a/controllers/gateway/config_resolver.go
+++ b/controllers/gateway/config_resolver.go
@@ -29,10 +29,10 @@ func newGatewayConfigResolver() gatewayConfigResolver {
 func (resolver *gatewayConfigResolverImpl) getLoadBalancerConfigForGateway(ctx context.Context, k8sClient client.Client, gw *gwv1.Gateway, gwClass *gwv1.GatewayClass) (elbv2gw.LoadBalancerConfiguration, error) {
 
 	// If the Gateway Class isn't accepted, we shouldn't try to reconcile this Gateway.
-	derivedStatus, _ := deriveGatewayClassAcceptedStatus(gwClass)
+	derivedStatusIndx, ok := deriveAcceptedConditionIndex(gwClass)
 
-	if derivedStatus != metav1.ConditionTrue {
-		return elbv2gw.LoadBalancerConfiguration{}, errors.Errorf("Unable to materialize gateway when gateway class [%s] is not accepted. GatewayClass status is %s", gwClass.Name, derivedStatus)
+	if !ok || gwClass.Status.Conditions[derivedStatusIndx].Status != metav1.ConditionTrue {
+		return elbv2gw.LoadBalancerConfiguration{}, errors.Errorf("Unable to materialize gateway when gateway class [%s] is not accepted", gwClass.Name)
 	}
 
 	gatewayClassLBConfig, err := resolver.configResolverFn(ctx, k8sClient, gwClass.Spec.ParametersRef)
diff --git a/controllers/gateway/gateway_controller.go b/controllers/gateway/gateway_controller.go
index f74a37ee37..866de8257d 100644
--- a/controllers/gateway/gateway_controller.go
+++ b/controllers/gateway/gateway_controller.go
@@ -3,9 +3,11 @@ package gateway
 import (
 	"context"
 	"fmt"
+	elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/client-go/tools/record"
@@ -35,6 +37,12 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/source"
 	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
 	gwalpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
+	"time"
+)
+
+const (
+	requeueMessage          = "Monitoring provisioning state"
+	statusUpdateRequeueTime = 2 * time.Minute
 )
 
 var _ Reconciler = &gatewayReconciler{}
@@ -86,6 +94,7 @@ func newGatewayReconciler(controllerName string, lbType elbv2model.LoadBalancerT
 		reconcileTracker:        reconcileTracker,
 		cfgResolver:             cfgResolver,
 		routeReconciler:         routeReconciler,
+		gatewayConditionUpdater: prepareGatewayConditionUpdate,
 	}
 }
 
@@ -107,6 +116,7 @@ type gatewayReconciler struct {
 	logger                  logr.Logger
 	metricsCollector        lbcmetrics.MetricCollector
 	reconcileTracker        func(namespaceName types.NamespacedName)
+	gatewayConditionUpdater func(gw *gwv1.Gateway, targetConditionType string, newStatus metav1.ConditionStatus, reason string, message string) bool
 
 	cfgResolver     gatewayConfigResolver
 	routeReconciler routeutils.RouteReconciler
@@ -186,12 +196,23 @@ func (r *gatewayReconciler) reconcileHelper(ctx context.Context, req reconcile.R
 	mergedLbConfig, err := r.cfgResolver.getLoadBalancerConfigForGateway(ctx, r.k8sClient, gw, gwClass)
 
 	if err != nil {
+		statusErr := r.updateGatewayStatusFailure(ctx, gw, gwv1.GatewayReasonInvalid, err)
+		if statusErr != nil {
+			r.logger.Error(statusErr, "Unable to update gateway status on failure to retrieve attached config")
+		}
 		return err
 	}
 
 	allRoutes, err := r.gatewayLoader.LoadRoutesForGateway(ctx, *gw, r.routeFilter, r.routeReconciler)
 
 	if err != nil {
+		var loaderErr routeutils.LoaderError
+		if errors.As(err, &loaderErr) {
+			statusErr := r.updateGatewayStatusFailure(ctx, gw, loaderErr.GetGatewayReason(), loaderErr)
+			if statusErr != nil {
+				r.logger.Error(statusErr, "Unable to update gateway status on failure to build routes")
+			}
+		}
 		return err
 	}
 
@@ -248,10 +269,6 @@ func (r *gatewayReconciler) reconcileUpdate(ctx context.Context, gw *gwv1.Gatewa
 	if err != nil {
 		return err
 	}
-	lbDNS, err := lb.DNSName().Resolve(ctx)
-	if err != nil {
-		return err
-	}
 
 	if !backendSGRequired {
 		if err := r.backendSGProvider.Release(ctx, networking.ResourceTypeGateway, []types.NamespacedName{k8s.NamespacedName(gw)}); err != nil {
@@ -259,7 +276,7 @@ func (r *gatewayReconciler) reconcileUpdate(ctx context.Context, gw *gwv1.Gatewa
 		}
 	}
 
-	if err = r.updateGatewayStatus(ctx, lbDNS, gw); err != nil {
+	if err = r.updateGatewayStatusSuccess(ctx, lb.Status, gw); err != nil {
 		r.eventRecorder.Event(gw, corev1.EventTypeWarning, k8s.GatewayEventReasonFailedUpdateStatus, fmt.Sprintf("Failed update status due to %v", err))
 		return err
 	}
@@ -295,28 +312,58 @@ func (r *gatewayReconciler) buildModel(ctx context.Context, gw *gwv1.Gateway, cf
 	return stack, lb, backendSGRequired, nil
 }
 
-func (r *gatewayReconciler) updateGatewayStatus(ctx context.Context, lbDNS string, gw *gwv1.Gateway) error {
-	// TODO Consider LB ARN.
+func (r *gatewayReconciler) updateGatewayStatusSuccess(ctx context.Context, lbStatus *elbv2model.LoadBalancerStatus, gw *gwv1.Gateway) error {
+	// LB Status should always be set, if it's not, we need to prevent NPE
+	if lbStatus == nil {
+		r.logger.Info("Unable to update Gateway Status due to null LB status")
+		return nil
+	}
+	gwOld := gw.DeepCopy()
+
+	var needPatch bool
+	var requeueNeeded bool
+	if isGatewayProgrammed(*lbStatus) {
+		needPatch = r.gatewayConditionUpdater(gw, string(gwv1.GatewayConditionProgrammed), metav1.ConditionTrue, string(gwv1.GatewayConditionProgrammed), lbStatus.LoadBalancerARN)
+	} else {
+		requeueNeeded = true
+	}
 
-	// Gateway Address Status
+	needPatch = r.gatewayConditionUpdater(gw, string(gwv1.GatewayConditionAccepted), metav1.ConditionTrue, string(gwv1.GatewayConditionAccepted), "") || needPatch
 	if len(gw.Status.Addresses) != 1 ||
-		gw.Status.Addresses[0].Value != "" ||
-		gw.Status.Addresses[0].Value != lbDNS {
-		gwOld := gw.DeepCopy()
+		gw.Status.Addresses[0].Value != lbStatus.DNSName {
 		ipAddressType := gwv1.HostnameAddressType
 		gw.Status.Addresses = []gwv1.GatewayStatusAddress{
 			{
 				Type:  &ipAddressType,
-				Value: lbDNS,
+				Value: lbStatus.DNSName,
 			},
 		}
+		needPatch = true
+	}
+
+	if needPatch {
 		if err := r.k8sClient.Status().Patch(ctx, gw, client.MergeFrom(gwOld)); err != nil {
 			return errors.Wrapf(err, "failed to update gw status: %v", k8s.NamespacedName(gw))
 		}
 	}
 
-	// TODO: Listener status ListenerStatus
-	// https://github.com/aws/aws-application-networking-k8s/blob/main/pkg/controllers/gateway_controller.go#L350
+	if requeueNeeded {
+		return runtime.NewRequeueNeededAfter(requeueMessage, statusUpdateRequeueTime)
+	}
+
+	return nil
+}
+
+func (r *gatewayReconciler) updateGatewayStatusFailure(ctx context.Context, gw *gwv1.Gateway, reason gwv1.GatewayConditionReason, err error) error {
+	gwOld := gw.DeepCopy()
+
+	needPatch := r.gatewayConditionUpdater(gw, string(gwv1.GatewayConditionAccepted), metav1.ConditionFalse, string(reason), err.Error())
+
+	if needPatch {
+		if err := r.k8sClient.Status().Patch(ctx, gw, client.MergeFrom(gwOld)); err != nil {
+			return errors.Wrapf(err, "failed to update gw status: %v", k8s.NamespacedName(gw))
+		}
+	}
 
 	return nil
 }
@@ -475,3 +522,12 @@ func (r *gatewayReconciler) setupNLBGatewayControllerWatches(ctrl controller.Con
 	return nil
 
 }
+
+func isGatewayProgrammed(lbStatus elbv2model.LoadBalancerStatus) bool {
+	if lbStatus.ProvisioningState == nil {
+		return false
+	}
+
+	return lbStatus.ProvisioningState.Code == elbv2types.LoadBalancerStateEnumActive || lbStatus.ProvisioningState.Code == elbv2types.LoadBalancerStateEnumActiveImpaired
+
+}
diff --git a/controllers/gateway/utils.go b/controllers/gateway/utils.go
index 9fb62b5c3d..50dfebcb46 100644
--- a/controllers/gateway/utils.go
+++ b/controllers/gateway/utils.go
@@ -14,16 +14,21 @@ import (
 	"strconv"
 	"strings"
 	"time"
+	"unicode/utf8"
 )
 
 const (
 	gatewayClassAnnotationLastProcessedConfig          = "elbv2.k8s.aws/last-processed-config"
 	gatewayClassAnnotationLastProcessedConfigTimestamp = gatewayClassAnnotationLastProcessedConfig + "-timestamp"
+
+	// The max message that can be stored in a condition
+	maxMessageLength = 32700
 )
 
+// updateGatewayClassLastProcessedConfig updates the gateway class annotations with the last processed lb config resource version or "" if no lb config is attached to the gatewayclass
 func updateGatewayClassLastProcessedConfig(ctx context.Context, k8sClient client.Client, gwClass *gwv1.GatewayClass, lbConf *elbv2gw.LoadBalancerConfiguration) error {
 
-	calculatedVersion := gatewayClassAnnotationLastProcessedConfig
+	calculatedVersion := ""
 
 	if lbConf != nil {
 		calculatedVersion = lbConf.ResourceVersion
@@ -36,12 +41,16 @@ func updateGatewayClassLastProcessedConfig(ctx context.Context, k8sClient client
 	}
 
 	gwClassOld := gwClass.DeepCopy()
+	if gwClass.Annotations == nil {
+		gwClass.Annotations = make(map[string]string)
+	}
 	gwClass.Annotations[gatewayClassAnnotationLastProcessedConfig] = calculatedVersion
 	gwClass.Annotations[gatewayClassAnnotationLastProcessedConfigTimestamp] = strconv.FormatInt(time.Now().Unix(), 10)
 
 	return k8sClient.Patch(ctx, gwClass, client.MergeFrom(gwClassOld))
 }
 
+// getStoredProcessedConfig retrieves the resource version attached to the lb config referenced by the gateway class or nil if no such mapping exists.
 func getStoredProcessedConfig(gwClass *gwv1.GatewayClass) *string {
 	var storedVersion *string
 
@@ -54,10 +63,20 @@ func getStoredProcessedConfig(gwClass *gwv1.GatewayClass) *string {
 	return storedVersion
 }
 
+// updateGatewayClassAcceptedCondition updates the 'accepted' condition on the gateway class to the passed in parameters. if no 'Accepted' condition exists, do nothing.
 func updateGatewayClassAcceptedCondition(ctx context.Context, k8sClient client.Client, gwClass *gwv1.GatewayClass, newStatus metav1.ConditionStatus, reason string, message string) error {
-	derivedStatus, indxToUpdate := deriveGatewayClassAcceptedStatus(gwClass)
+	indxToUpdate, ok := deriveAcceptedConditionIndex(gwClass)
+
+	if ok {
+
+		storedStatus := gwClass.Status.Conditions[indxToUpdate].Status
+		storedMessage := gwClass.Status.Conditions[indxToUpdate].Message
+		storedReason := gwClass.Status.Conditions[indxToUpdate].Reason
+
+		if storedStatus == newStatus && storedMessage == message && storedReason == reason {
+			return nil
+		}
 
-	if indxToUpdate != -1 && derivedStatus != newStatus {
 		gwClassOld := gwClass.DeepCopy()
 		gwClass.Status.Conditions[indxToUpdate].LastTransitionTime = metav1.NewTime(time.Now())
 		gwClass.Status.Conditions[indxToUpdate].ObservedGeneration = gwClass.Generation
@@ -71,15 +90,56 @@ func updateGatewayClassAcceptedCondition(ctx context.Context, k8sClient client.C
 	return nil
 }
 
-func deriveGatewayClassAcceptedStatus(gwClass *gwv1.GatewayClass) (metav1.ConditionStatus, int) {
+// prepareGatewayConditionUpdate inserts the necessary data into the condition field of the gateway. The caller should patch the corresponding gateway. Returns false when no change was performed.
+func prepareGatewayConditionUpdate(gw *gwv1.Gateway, targetConditionType string, newStatus metav1.ConditionStatus, reason string, message string) bool {
+
+	indxToUpdate := -1
+	var derivedCondition metav1.Condition
+	for i, condition := range gw.Status.Conditions {
+		if condition.Type == targetConditionType {
+			indxToUpdate = i
+			derivedCondition = condition
+			break
+		}
+	}
+
+	// 32768 is the max message limit
+	truncatedMessage := truncateMessage(message)
+
+	if indxToUpdate != -1 {
+		if derivedCondition.Status != newStatus || derivedCondition.Message != truncatedMessage || derivedCondition.Reason != reason {
+			gw.Status.Conditions[indxToUpdate].LastTransitionTime = metav1.NewTime(time.Now())
+			gw.Status.Conditions[indxToUpdate].ObservedGeneration = gw.Generation
+			gw.Status.Conditions[indxToUpdate].Status = newStatus
+			gw.Status.Conditions[indxToUpdate].Message = truncatedMessage
+			gw.Status.Conditions[indxToUpdate].Reason = reason
+			return true
+		}
+	}
+	return false
+}
+
+func truncateMessage(s string) string {
+	if utf8.RuneCountInString(s) <= maxMessageLength {
+		return s
+	}
+
+	runes := []rune(s)
+	return string(runes[:maxMessageLength]) + "..."
+}
+
+// deriveAcceptedConditionIndex returns the index of the condition pertaining to the accepted condition.
+// -1 if the condition doesn't exist
+func deriveAcceptedConditionIndex(gwClass *gwv1.GatewayClass) (int, bool) {
 	for i, v := range gwClass.Status.Conditions {
 		if v.Type == string(gwv1.GatewayClassReasonAccepted) {
-			return v.Status, i
+			return i, true
 		}
 	}
-	return metav1.ConditionFalse, -1
+	return -1, false
 }
 
+// resolveLoadBalancerConfig returns the lb config referenced in the ParametersReference.
 func resolveLoadBalancerConfig(ctx context.Context, k8sClient client.Client, reference *gwv1.ParametersReference) (*elbv2gw.LoadBalancerConfiguration, error) {
 	var lbConf *elbv2gw.LoadBalancerConfiguration
 
diff --git a/controllers/gateway/utils_test.go b/controllers/gateway/utils_test.go
index bd9b2a6c55..868cf77bd6 100644
--- a/controllers/gateway/utils_test.go
+++ b/controllers/gateway/utils_test.go
@@ -1,11 +1,760 @@
 package gateway
 
 import (
+	"context"
+	"fmt"
+	awssdk "github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/stretchr/testify/assert"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	elbv2gw "sigs.k8s.io/aws-load-balancer-controller/apis/gateway/v1beta1"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/gateway/routeutils"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/testutils"
+	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
+	"strconv"
 	"testing"
+	"time"
 )
 
+func Test_updateGatewayClassLastProcessedConfig(t *testing.T) {
+	testCases := []struct {
+		name            string
+		gwClass         gwv1.GatewayClass
+		lbConf          *elbv2gw.LoadBalancerConfiguration
+		expectedVersion string
+		noPatch         bool
+	}{
+		{
+			name: "no lb conf, no prior annotation",
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name: "gwclass",
+				},
+			},
+			expectedVersion: "",
+		},
+		{
+			name: "no lb conf, with prior annotation",
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name: "gwclass",
+					Annotations: map[string]string{
+						gatewayClassAnnotationLastProcessedConfig:          "foo",
+						gatewayClassAnnotationLastProcessedConfigTimestamp: "0",
+					},
+				},
+			},
+			expectedVersion: "",
+		},
+		{
+			name: "with lb conf, no prior annotation",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				ObjectMeta: v1.ObjectMeta{
+					ResourceVersion: "bar",
+				},
+			},
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name: "gwclass",
+				},
+			},
+			expectedVersion: "bar",
+		},
+		{
+			name: "with lb conf, with prior annotation",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				ObjectMeta: v1.ObjectMeta{
+					ResourceVersion: "bar",
+				},
+			},
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name: "gwclass",
+					Annotations: map[string]string{
+						gatewayClassAnnotationLastProcessedConfig:          "foo",
+						gatewayClassAnnotationLastProcessedConfigTimestamp: "0",
+					},
+				},
+			},
+			expectedVersion: "bar",
+		},
+		{
+			name: "no change in stored version should not trigger patch",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				ObjectMeta: v1.ObjectMeta{
+					ResourceVersion: "foo",
+				},
+			},
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name: "gwclass",
+					Annotations: map[string]string{
+						gatewayClassAnnotationLastProcessedConfig:          "foo",
+						gatewayClassAnnotationLastProcessedConfigTimestamp: "10",
+					},
+				},
+			},
+			expectedVersion: "foo",
+			noPatch:         true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			client := testutils.GenerateTestClient()
+			original := tc.gwClass.DeepCopy()
+			err := client.Create(context.Background(), original)
+			assert.NoError(t, err)
+			err = updateGatewayClassLastProcessedConfig(context.Background(), client, original, tc.lbConf)
+			assert.NoError(t, err)
+			stored := &gwv1.GatewayClass{}
+			err = client.Get(context.Background(), k8s.NamespacedName(original), stored)
+			assert.NoError(t, err)
+			assert.Equal(t, tc.expectedVersion, stored.Annotations[gatewayClassAnnotationLastProcessedConfig])
+
+			ts, err := strconv.Atoi(stored.Annotations[gatewayClassAnnotationLastProcessedConfigTimestamp])
+			assert.NoError(t, err)
+			assert.NotZero(t, ts)
+			if tc.noPatch {
+				assert.Equal(t, tc.gwClass.Annotations[gatewayClassAnnotationLastProcessedConfigTimestamp], stored.Annotations[gatewayClassAnnotationLastProcessedConfigTimestamp])
+			}
+		})
+	}
+}
+
+func Test_updateGatewayClassAcceptedCondition(t *testing.T) {
+	testCases := []struct {
+		name    string
+		gwClass gwv1.GatewayClass
+		status  metav1.ConditionStatus
+		reason  string
+		message string
+
+		expectedConditions []metav1.Condition
+		noPatch            bool
+	}{
+		{
+			name: "nil conditions",
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name: "gwclass",
+				},
+			},
+		},
+		{
+			name: "no conditions",
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name: "gwclass",
+				},
+				Status: gwv1.GatewayClassStatus{
+					Conditions: make([]v1.Condition, 0),
+				},
+			},
+		},
+		{
+			name:    "flip condition to true",
+			status:  metav1.ConditionTrue,
+			reason:  "flip to true",
+			message: "test message",
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name:       "gwclass-flip-true",
+					Generation: 100,
+				},
+				Status: gwv1.GatewayClassStatus{
+					Conditions: []v1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               string(gwv1.GatewayClassReasonAccepted),
+							Status:             metav1.ConditionFalse,
+							ObservedGeneration: 1000,
+							Reason:             "",
+							Message:            "",
+						},
+					},
+				},
+			},
+			expectedConditions: []v1.Condition{
+				{
+					Type:               "other condition",
+					Status:             metav1.ConditionTrue,
+					ObservedGeneration: 1000,
+					Reason:             "other reason",
+					Message:            "other message",
+				},
+				{
+					Type:               string(gwv1.GatewayClassReasonAccepted),
+					Status:             metav1.ConditionTrue,
+					ObservedGeneration: 100,
+					Reason:             "flip to true",
+					Message:            "test message",
+				},
+			},
+		},
+		{
+			name:    "flip condition to false",
+			status:  metav1.ConditionFalse,
+			reason:  "flip to false",
+			message: "test message",
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name:       "gwclass-flip",
+					Generation: 100,
+				},
+				Status: gwv1.GatewayClassStatus{
+					Conditions: []v1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               string(gwv1.GatewayClassReasonAccepted),
+							Status:             metav1.ConditionFalse,
+							ObservedGeneration: 1000,
+							Reason:             "",
+							Message:            "",
+						},
+					},
+				},
+			},
+			expectedConditions: []v1.Condition{
+				{
+					Type:               "other condition",
+					Status:             metav1.ConditionTrue,
+					ObservedGeneration: 1000,
+					Reason:             "other reason",
+					Message:            "other message",
+				},
+				{
+					Type:               string(gwv1.GatewayClassReasonAccepted),
+					Status:             metav1.ConditionFalse,
+					ObservedGeneration: 100,
+					Reason:             "flip to false",
+					Message:            "test message",
+				},
+			},
+		},
+		{
+			name:    "no change results in no patch",
+			status:  metav1.ConditionFalse,
+			reason:  "reason",
+			message: "msg",
+			gwClass: gwv1.GatewayClass{
+				ObjectMeta: v1.ObjectMeta{
+					Name:       "gwclass-flip",
+					Generation: 100,
+				},
+				Status: gwv1.GatewayClassStatus{
+					Conditions: []v1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               string(gwv1.GatewayClassReasonAccepted),
+							Status:             metav1.ConditionFalse,
+							ObservedGeneration: 1000,
+							Reason:             "reason",
+							Message:            "msg",
+						},
+					},
+				},
+			},
+			expectedConditions: []v1.Condition{
+				{
+					Type:               "other condition",
+					Status:             metav1.ConditionTrue,
+					ObservedGeneration: 1000,
+					Reason:             "other reason",
+					Message:            "other message",
+				},
+				{
+					Type:               string(gwv1.GatewayClassReasonAccepted),
+					Status:             metav1.ConditionFalse,
+					ObservedGeneration: 1000,
+					Reason:             "reason",
+					Message:            "msg",
+				},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			mockClient := testutils.GenerateTestClient()
+			err := mockClient.Create(context.Background(), &tc.gwClass)
+			assert.NoError(t, err)
+			time.Sleep(1 * time.Second)
+
+			stored := &gwv1.GatewayClass{}
+			err = mockClient.Get(context.Background(), k8s.NamespacedName(&tc.gwClass), stored)
+			assert.NoError(t, err)
+
+			err = updateGatewayClassAcceptedCondition(context.Background(), mockClient, tc.gwClass.DeepCopy(), tc.status, tc.reason, tc.message)
+			assert.NoError(t, err)
+			stored = &gwv1.GatewayClass{}
+			err = mockClient.Get(context.Background(), k8s.NamespacedName(&tc.gwClass), stored)
+			assert.NoError(t, err)
+
+			fixedTime := metav1.NewTime(time.Now())
+
+			// In order to use equals(), we need to make the time fields are fixed.
+			if tc.expectedConditions != nil {
+				for i := range tc.expectedConditions {
+					tmp := &tc.expectedConditions[i]
+					tmp.LastTransitionTime = fixedTime
+				}
+			}
+
+			if stored.Status.Conditions != nil {
+				for i := range stored.Status.Conditions {
+					tmp := &stored.Status.Conditions[i]
+					tmp.LastTransitionTime = fixedTime
+				}
+			}
+
+			assert.Equal(t, tc.expectedConditions, stored.Status.Conditions)
+		})
+	}
+}
+
+func Test_prepareGatewayConditionUpdate(t *testing.T) {
+
+	longString := ""
+	for i := 0; i < 50000; i++ {
+		longString = fmt.Sprintf("%s%s", longString, "a")
+	}
+	truncatedString := ""
+	for i := 0; i < 32700; i++ {
+		truncatedString = fmt.Sprintf("%s%s", truncatedString, "a")
+	}
+	truncatedString = fmt.Sprintf("%s...", truncatedString)
+
+	testCases := []struct {
+		name                string
+		gw                  gwv1.Gateway
+		targetConditionType string
+		newStatus           metav1.ConditionStatus
+		reason              string
+		message             string
+
+		expectedGw gwv1.Gateway
+		expected   bool
+	}{
+		{
+			name: "target condition not found",
+			gw: gwv1.Gateway{
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			expectedGw: gwv1.Gateway{
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			targetConditionType: string(gwv1.GatewayConditionAccepted),
+			newStatus:           metav1.ConditionTrue,
+			reason:              "other reason",
+			message:             "other message",
+		},
+		{
+			name: "target condition found",
+			gw: gwv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Generation: 50,
+				},
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:    string(gwv1.GatewayConditionAccepted),
+							Status:  metav1.ConditionFalse,
+							Reason:  "other reason",
+							Message: "other message",
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			expectedGw: gwv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Generation: 50,
+				},
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               string(gwv1.GatewayConditionAccepted),
+							Status:             metav1.ConditionTrue,
+							Reason:             "new reason",
+							Message:            "new message",
+							ObservedGeneration: 50,
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			targetConditionType: string(gwv1.GatewayConditionAccepted),
+			newStatus:           metav1.ConditionTrue,
+			reason:              "new reason",
+			message:             "new message",
+			expected:            true,
+		},
+		{
+			name: "target condition found - long message truncated",
+			gw: gwv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Generation: 50,
+				},
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:    string(gwv1.GatewayConditionAccepted),
+							Status:  metav1.ConditionFalse,
+							Reason:  "other reason",
+							Message: "other message",
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			expectedGw: gwv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Generation: 50,
+				},
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               string(gwv1.GatewayConditionAccepted),
+							Status:             metav1.ConditionTrue,
+							Reason:             "new reason",
+							Message:            truncatedString,
+							ObservedGeneration: 50,
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			targetConditionType: string(gwv1.GatewayConditionAccepted),
+			newStatus:           metav1.ConditionTrue,
+			reason:              "new reason",
+			message:             longString,
+			expected:            true,
+		},
+		{
+			name: "target condition found already correct",
+			gw: gwv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Generation: 50,
+				},
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               string(gwv1.GatewayConditionAccepted),
+							Status:             metav1.ConditionTrue,
+							Reason:             "new reason",
+							Message:            "new message",
+							ObservedGeneration: 1000,
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			expectedGw: gwv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Generation: 50,
+				},
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               string(gwv1.GatewayConditionAccepted),
+							Status:             metav1.ConditionTrue,
+							Reason:             "new reason",
+							Message:            "new message",
+							ObservedGeneration: 1000,
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			targetConditionType: string(gwv1.GatewayConditionAccepted),
+			newStatus:           metav1.ConditionTrue,
+			reason:              "new reason",
+			message:             "new message",
+		},
+		{
+			name: "target condition found - long message truncated",
+			gw: gwv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Generation: 50,
+				},
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               string(gwv1.GatewayConditionAccepted),
+							Status:             metav1.ConditionTrue,
+							Reason:             "other reason",
+							Message:            truncatedString,
+							ObservedGeneration: 1000,
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			expectedGw: gwv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Generation: 50,
+				},
+				Status: gwv1.GatewayStatus{
+					Conditions: []metav1.Condition{
+						{
+							Type:               "other condition",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1000,
+							Reason:             "other reason",
+							Message:            "other message",
+						},
+						{
+							Type:               string(gwv1.GatewayConditionAccepted),
+							Status:             metav1.ConditionTrue,
+							Reason:             "other reason",
+							Message:            truncatedString,
+							ObservedGeneration: 1000,
+						},
+						{
+							Type:               "other condition2",
+							Status:             metav1.ConditionTrue,
+							ObservedGeneration: 1001,
+							Reason:             "other reason2",
+							Message:            "other message2",
+						},
+					},
+				},
+			},
+			targetConditionType: string(gwv1.GatewayConditionAccepted),
+			newStatus:           metav1.ConditionTrue,
+			reason:              "other reason",
+			message:             longString,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			res := prepareGatewayConditionUpdate(&tc.gw, tc.targetConditionType, tc.newStatus, tc.reason, tc.message)
+
+			// In order to use equals(), we need to make the time fields are fixed.
+			fixedTime := metav1.NewTime(time.Now())
+			if tc.gw.Status.Conditions != nil {
+				for i := range tc.gw.Status.Conditions {
+					tmp := &tc.gw.Status.Conditions[i]
+					tmp.LastTransitionTime = fixedTime
+				}
+			}
+
+			if tc.expectedGw.Status.Conditions != nil {
+				for i := range tc.expectedGw.Status.Conditions {
+					tmp := &tc.expectedGw.Status.Conditions[i]
+					tmp.LastTransitionTime = fixedTime
+				}
+			}
+
+			assert.Equal(t, tc.expected, res)
+			assert.Equal(t, tc.expectedGw, tc.gw)
+		})
+	}
+}
+
+func Test_resolveLoadBalancerConfig(t *testing.T) {
+	testCases := []struct {
+		name      string
+		reference *gwv1.ParametersReference
+		lbConf    *elbv2gw.LoadBalancerConfiguration
+		expectErr bool
+	}{
+		{
+			name: "lb conf found",
+			reference: &gwv1.ParametersReference{
+				Name:      "foo",
+				Namespace: (*gwv1.Namespace)(awssdk.String("ns")),
+			},
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "foo",
+					Namespace: "ns",
+				},
+			},
+		},
+		{
+			name: "no lb conf",
+			reference: &gwv1.ParametersReference{
+				Name:      "foo",
+				Namespace: (*gwv1.Namespace)(awssdk.String("ns")),
+			},
+			expectErr: true,
+		},
+		{
+			name: "no namespace",
+			reference: &gwv1.ParametersReference{
+				Name: "foo",
+			},
+			expectErr: true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			mockClient := testutils.GenerateTestClient()
+			if tc.lbConf != nil {
+				err := mockClient.Create(context.Background(), tc.lbConf)
+				assert.NoError(t, err)
+			}
+			time.Sleep(1 * time.Second)
+
+			res, err := resolveLoadBalancerConfig(context.Background(), mockClient, tc.reference)
+			if tc.expectErr {
+				assert.Error(t, err)
+				return
+			}
+			assert.NoError(t, err)
+			assert.Equal(t, tc.lbConf, res)
+		})
+	}
+}
+
 func Test_generateRouteList(t *testing.T) {
 	testCases := []struct {
 		name     string
diff --git a/pkg/deploy/elbv2/load_balancer_manager.go b/pkg/deploy/elbv2/load_balancer_manager.go
index 093991679c..447ccabefc 100644
--- a/pkg/deploy/elbv2/load_balancer_manager.go
+++ b/pkg/deploy/elbv2/load_balancer_manager.go
@@ -391,8 +391,9 @@ func buildSDKSubnetMapping(modelSubnetMapping elbv2model.SubnetMapping) elbv2typ
 
 func buildResLoadBalancerStatus(sdkLB LoadBalancerWithTags) elbv2model.LoadBalancerStatus {
 	return elbv2model.LoadBalancerStatus{
-		LoadBalancerARN: awssdk.ToString(sdkLB.LoadBalancer.LoadBalancerArn),
-		DNSName:         awssdk.ToString(sdkLB.LoadBalancer.DNSName),
+		LoadBalancerARN:   awssdk.ToString(sdkLB.LoadBalancer.LoadBalancerArn),
+		DNSName:           awssdk.ToString(sdkLB.LoadBalancer.DNSName),
+		ProvisioningState: sdkLB.LoadBalancer.State,
 	}
 }
 
diff --git a/pkg/deploy/elbv2/load_balancer_manager_test.go b/pkg/deploy/elbv2/load_balancer_manager_test.go
index 02cdb9b6e1..0064b5b879 100644
--- a/pkg/deploy/elbv2/load_balancer_manager_test.go
+++ b/pkg/deploy/elbv2/load_balancer_manager_test.go
@@ -429,12 +429,20 @@ func Test_buildResLoadBalancerStatus(t *testing.T) {
 					LoadBalancer: &elbv2types.LoadBalancer{
 						LoadBalancerArn: awssdk.String("my-arn"),
 						DNSName:         awssdk.String("www.example.com"),
+						State: &elbv2types.LoadBalancerState{
+							Code:   elbv2types.LoadBalancerStateEnumProvisioning,
+							Reason: awssdk.String("foo"),
+						},
 					},
 				},
 			},
 			want: elbv2model.LoadBalancerStatus{
 				LoadBalancerARN: "my-arn",
 				DNSName:         "www.example.com",
+				ProvisioningState: &elbv2types.LoadBalancerState{
+					Code:   elbv2types.LoadBalancerStateEnumProvisioning,
+					Reason: awssdk.String("foo"),
+				},
 			},
 		},
 	}
diff --git a/pkg/gateway/model/model_build_target_group.go b/pkg/gateway/model/model_build_target_group.go
index 11d80d1828..a6b990ed9d 100644
--- a/pkg/gateway/model/model_build_target_group.go
+++ b/pkg/gateway/model/model_build_target_group.go
@@ -31,7 +31,7 @@ type targetGroupBuilder interface {
 	buildTargetGroup(stack core.Stack,
 		gw *gwv1.Gateway, lbConfig elbv2gw.LoadBalancerConfiguration, lbIPType elbv2model.IPAddressType, routeDescriptor routeutils.RouteDescriptor, backend routeutils.Backend, backendSGIDToken core.StringToken) (*elbv2model.TargetGroup, error)
 	buildTargetGroupSpec(gw *gwv1.Gateway, route routeutils.RouteDescriptor, lbConfig elbv2gw.LoadBalancerConfiguration, lbIPType elbv2model.IPAddressType, backend routeutils.Backend, targetGroupProps *elbv2gw.TargetGroupProps) (elbv2model.TargetGroupSpec, error)
-	buildTargetGroupBindingSpec(tgProps *elbv2gw.TargetGroupProps, tgSpec elbv2model.TargetGroupSpec, nodeSelector *metav1.LabelSelector, backend routeutils.Backend, backendSGIDToken core.StringToken) elbv2model.TargetGroupBindingResourceSpec
+	buildTargetGroupBindingSpec(gw *gwv1.Gateway, tgProps *elbv2gw.TargetGroupProps, tgSpec elbv2model.TargetGroupSpec, nodeSelector *metav1.LabelSelector, backend routeutils.Backend, backendSGIDToken core.StringToken) elbv2model.TargetGroupBindingResourceSpec
 }
 
 type targetGroupBuilderImpl struct {
@@ -108,7 +108,7 @@ func (t *targetGroupBuilderImpl) buildTargetGroup(stack core.Stack,
 		return nil, err
 	}
 	nodeSelector := t.buildTargetGroupBindingNodeSelector(targetGroupProps, tgSpec.TargetType)
-	bindingSpec := t.buildTargetGroupBindingSpec(targetGroupProps, tgSpec, nodeSelector, backend, backendSGIDToken)
+	bindingSpec := t.buildTargetGroupBindingSpec(gw, targetGroupProps, tgSpec, nodeSelector, backend, backendSGIDToken)
 
 	tgOut := buildTargetGroupOutput{
 		targetGroupSpec: tgSpec,
@@ -130,7 +130,7 @@ func (builder *targetGroupBuilderImpl) getTargetGroupProps(routeDescriptor route
 	return targetGroupProps
 }
 
-func (builder *targetGroupBuilderImpl) buildTargetGroupBindingSpec(tgProps *elbv2gw.TargetGroupProps, tgSpec elbv2model.TargetGroupSpec, nodeSelector *metav1.LabelSelector, backend routeutils.Backend, backendSGIDToken core.StringToken) elbv2model.TargetGroupBindingResourceSpec {
+func (builder *targetGroupBuilderImpl) buildTargetGroupBindingSpec(gw *gwv1.Gateway, tgProps *elbv2gw.TargetGroupProps, tgSpec elbv2model.TargetGroupSpec, nodeSelector *metav1.LabelSelector, backend routeutils.Backend, backendSGIDToken core.StringToken) elbv2model.TargetGroupBindingResourceSpec {
 	targetType := elbv2api.TargetType(tgSpec.TargetType)
 	targetPort := backend.ServicePort.TargetPort
 	if targetType == elbv2api.TargetTypeInstance {
@@ -140,11 +140,30 @@ func (builder *targetGroupBuilderImpl) buildTargetGroupBindingSpec(tgProps *elbv
 
 	multiClusterEnabled := builder.buildTargetGroupBindingMultiClusterFlag(tgProps)
 
+	annotations := make(map[string]string)
+	labels := make(map[string]string)
+
+	if gw != nil && gw.Spec.Infrastructure != nil {
+		if gw.Spec.Infrastructure.Annotations != nil {
+			for k, v := range gw.Spec.Infrastructure.Annotations {
+				annotations[string(k)] = string(v)
+			}
+		}
+
+		if gw.Spec.Infrastructure.Labels != nil {
+			for k, v := range gw.Spec.Infrastructure.Labels {
+				labels[string(k)] = string(v)
+			}
+		}
+	}
+
 	return elbv2model.TargetGroupBindingResourceSpec{
 		Template: elbv2model.TargetGroupBindingTemplate{
 			ObjectMeta: metav1.ObjectMeta{
-				Namespace: backend.Service.Namespace,
-				Name:      tgSpec.Name,
+				Namespace:   backend.Service.Namespace,
+				Name:        tgSpec.Name,
+				Annotations: annotations,
+				Labels:      labels,
 			},
 			Spec: elbv2model.TargetGroupBindingSpec{
 				TargetGroupARN: nil, // This should get filled in later!
diff --git a/pkg/gateway/model/model_build_target_group_test.go b/pkg/gateway/model/model_build_target_group_test.go
index 4d57f5ae13..35663c5b03 100644
--- a/pkg/gateway/model/model_build_target_group_test.go
+++ b/pkg/gateway/model/model_build_target_group_test.go
@@ -360,8 +360,10 @@ func Test_buildTargetGroupBindingSpec(t *testing.T) {
 			expectedTgBindingSpec: elbv2model.TargetGroupBindingResourceSpec{
 				Template: elbv2model.TargetGroupBindingTemplate{
 					ObjectMeta: metav1.ObjectMeta{
-						Namespace: "my-svc-ns",
-						Name:      "k8s-myrouten-myroute-d02da2803b",
+						Namespace:   "my-svc-ns",
+						Name:        "k8s-myrouten-myroute-d02da2803b",
+						Annotations: make(map[string]string),
+						Labels:      make(map[string]string),
 					},
 					Spec: elbv2model.TargetGroupBindingSpec{
 						TargetType: &instanceType,
@@ -437,8 +439,10 @@ func Test_buildTargetGroupBindingSpec(t *testing.T) {
 			expectedTgBindingSpec: elbv2model.TargetGroupBindingResourceSpec{
 				Template: elbv2model.TargetGroupBindingTemplate{
 					ObjectMeta: metav1.ObjectMeta{
-						Namespace: "my-svc-ns",
-						Name:      "k8s-myrouten-myroute-d146029dfb",
+						Namespace:   "my-svc-ns",
+						Name:        "k8s-myrouten-myroute-d146029dfb",
+						Annotations: make(map[string]string),
+						Labels:      make(map[string]string),
 					},
 					Spec: elbv2model.TargetGroupBindingSpec{
 						TargetType: &instanceType,
@@ -509,8 +513,10 @@ func Test_buildTargetGroupBindingSpec(t *testing.T) {
 			expectedTgBindingSpec: elbv2model.TargetGroupBindingResourceSpec{
 				Template: elbv2model.TargetGroupBindingTemplate{
 					ObjectMeta: metav1.ObjectMeta{
-						Namespace: "my-svc-ns",
-						Name:      "k8s-myrouten-myroute-d9d6c4e6eb",
+						Namespace:   "my-svc-ns",
+						Name:        "k8s-myrouten-myroute-d9d6c4e6eb",
+						Annotations: make(map[string]string),
+						Labels:      make(map[string]string),
 					},
 					Spec: elbv2model.TargetGroupBindingSpec{
 						TargetType: &ipType,
@@ -583,11 +589,106 @@ func Test_buildTargetGroupBindingSpec(t *testing.T) {
 				TargetGroupAttributes: make([]elbv2model.TargetGroupAttribute, 0),
 				Tags:                  make(map[string]string),
 			},
+			expectedTgBindingSpec: elbv2model.TargetGroupBindingResourceSpec{
+				Template: elbv2model.TargetGroupBindingTemplate{
+					ObjectMeta: metav1.ObjectMeta{
+						Namespace:   "my-svc-ns",
+						Name:        "k8s-myrouten-myroute-400113e816",
+						Annotations: make(map[string]string),
+						Labels:      make(map[string]string),
+					},
+					Spec: elbv2model.TargetGroupBindingSpec{
+						TargetType: &ipType,
+						ServiceRef: elbv2api.ServiceReference{
+							Name: "my-svc",
+							Port: intstr.FromInt32(80), // TODO - Figure out why this port is added and not the node port.
+						},
+						IPAddressType: elbv2api.TargetGroupIPAddressType(elbv2model.IPAddressTypeIPV4),
+						VpcID:         "vpc-xxx",
+					},
+				},
+			},
+		},
+		{
+			name:                     "no tg config - ip - alb - add infra annotations / labels",
+			tags:                     make(map[string]string),
+			lbType:                   elbv2model.LoadBalancerTypeApplication,
+			disableRestrictedSGRules: false,
+			defaultTargetType:        string(elbv2model.TargetTypeIP),
+			gateway: &gwv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: "my-gw-ns",
+					Name:      "my-gw",
+				},
+				Spec: gwv1.GatewaySpec{
+					Infrastructure: &gwv1.GatewayInfrastructure{
+						Annotations: map[gwv1.AnnotationKey]gwv1.AnnotationValue{
+							"foo": "bar",
+						},
+						Labels: map[gwv1.LabelKey]gwv1.LabelValue{
+							"labelfoo": "labelbar",
+						},
+					},
+				},
+			},
+			route: &routeutils.MockRoute{
+				Kind:      routeutils.HTTPRouteKind,
+				Name:      "my-route",
+				Namespace: "my-route-ns",
+			},
+			backend: routeutils.Backend{
+				Service: &corev1.Service{
+					ObjectMeta: metav1.ObjectMeta{
+						Namespace: "my-svc-ns",
+						Name:      "my-svc",
+					},
+				},
+				ServicePort: &corev1.ServicePort{
+					Protocol: corev1.ProtocolTCP,
+					Port:     80,
+					TargetPort: intstr.IntOrString{
+						IntVal: 80,
+						Type:   intstr.Int,
+					},
+					NodePort: 8080,
+				},
+			},
+			expectedTgSpec: elbv2model.TargetGroupSpec{
+				Name:            "k8s-myrouten-myroute-400113e816",
+				TargetType:      elbv2model.TargetTypeIP,
+				Port:            awssdk.Int32(80),
+				Protocol:        elbv2model.ProtocolHTTP,
+				ProtocolVersion: &http1,
+				IPAddressType:   elbv2model.TargetGroupIPAddressTypeIPv4,
+				HealthCheckConfig: &elbv2model.TargetGroupHealthCheckConfig{
+					Port: &intstr.IntOrString{
+						StrVal: shared_constants.HealthCheckPortTrafficPort,
+						Type:   intstr.String,
+					},
+					Path: awssdk.String("/"),
+					Matcher: &elbv2model.HealthCheckMatcher{
+						HTTPCode: awssdk.String("200-399"),
+					},
+					Protocol:                elbv2model.ProtocolHTTP,
+					IntervalSeconds:         awssdk.Int32(15),
+					TimeoutSeconds:          awssdk.Int32(5),
+					HealthyThresholdCount:   awssdk.Int32(3),
+					UnhealthyThresholdCount: awssdk.Int32(3),
+				},
+				TargetGroupAttributes: make([]elbv2model.TargetGroupAttribute, 0),
+				Tags:                  make(map[string]string),
+			},
 			expectedTgBindingSpec: elbv2model.TargetGroupBindingResourceSpec{
 				Template: elbv2model.TargetGroupBindingTemplate{
 					ObjectMeta: metav1.ObjectMeta{
 						Namespace: "my-svc-ns",
 						Name:      "k8s-myrouten-myroute-400113e816",
+						Annotations: map[string]string{
+							"foo": "bar",
+						},
+						Labels: map[string]string{
+							"labelfoo": "labelbar",
+						},
 					},
 					Spec: elbv2model.TargetGroupBindingSpec{
 						TargetType: &ipType,
@@ -613,7 +714,7 @@ func Test_buildTargetGroupBindingSpec(t *testing.T) {
 
 			builder := newTargetGroupBuilder("my-cluster", "vpc-xxx", tagger, tc.lbType, tc.disableRestrictedSGRules, tc.defaultTargetType)
 
-			out := builder.buildTargetGroupBindingSpec(nil, tc.expectedTgSpec, nil, tc.backend, nil)
+			out := builder.buildTargetGroupBindingSpec(tc.gateway, nil, tc.expectedTgSpec, nil, tc.backend, nil)
 
 			assert.Equal(t, tc.expectedTgBindingSpec, out)
 		})
diff --git a/pkg/gateway/routeutils/backend.go b/pkg/gateway/routeutils/backend.go
index 31816272e9..54f2c44f48 100644
--- a/pkg/gateway/routeutils/backend.go
+++ b/pkg/gateway/routeutils/backend.go
@@ -31,7 +31,8 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpeci
 
 	// We only support references of type service.
 	if backendRef.Kind != nil && *backendRef.Kind != "Service" {
-		return nil, nil
+		initialErrorMessage := "Backend Ref must be of kind 'Service'"
+		return nil, wrapError(errors.Errorf("%s", generateInvalidMessageWithRouteDetails(initialErrorMessage, routeKind, routeIdentifier)), gwv1.GatewayReasonListenersNotValid, gwv1.RouteReasonInvalidKind)
 	}
 
 	if backendRef.Weight != nil && *backendRef.Weight == 0 {
@@ -39,7 +40,8 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpeci
 	}
 
 	if backendRef.Port == nil {
-		return nil, errors.Errorf("Missing port in backend reference")
+		initialErrorMessage := "Port is required"
+		return nil, wrapError(errors.Errorf("%s", generateInvalidMessageWithRouteDetails(initialErrorMessage, routeKind, routeIdentifier)), gwv1.GatewayReasonListenersNotValid, gwv1.RouteReasonUnsupportedValue)
 	}
 
 	var svcNamespace string
@@ -58,6 +60,7 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpeci
 	if svcNamespace != routeIdentifier.Namespace {
 		allowed, err := referenceGrantCheck(ctx, k8sClient, svcIdentifier, routeIdentifier, routeKind)
 		if err != nil {
+			// Currently, this API only fails for a k8s related error message, hence no status update.
 			return nil, errors.Wrapf(err, "Unable to perform reference grant check")
 		}
 
@@ -72,9 +75,17 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpeci
 	svc := &corev1.Service{}
 	err := k8sClient.Get(ctx, svcIdentifier, svc)
 	if err != nil {
+
+		convertToNotFoundError := client.IgnoreNotFound(err)
+
+		if convertToNotFoundError == nil {
+			// Svc not found, post an updated status.
+			initialErrorMessage := fmt.Sprintf("Service (%s:%s) not found)", svcIdentifier.Namespace, svcIdentifier.Name)
+			return nil, wrapError(errors.Errorf("%s", generateInvalidMessageWithRouteDetails(initialErrorMessage, routeKind, routeIdentifier)), gwv1.GatewayReasonListenersNotValid, gwv1.RouteReasonBackendNotFound)
+		}
+		// Otherwise, general error. No need for status update.
 		return nil, errors.Wrap(err, fmt.Sprintf("Unable to fetch svc object %+v", svcIdentifier))
 	}
-
 	var servicePort *corev1.ServicePort
 
 	for _, svcPort := range svc.Spec.Ports {
@@ -87,11 +98,13 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpeci
 	tgConfig, err := lookUpTargetGroupConfiguration(ctx, k8sClient, k8s.NamespacedName(svc))
 
 	if err != nil {
+		// As of right now, this error can only be thrown because of a k8s api error hence no status update.
 		return nil, errors.Wrap(err, fmt.Sprintf("Unable to fetch tg config object"))
 	}
 
 	if servicePort == nil {
-		return nil, errors.Errorf("Unable to find service port for port %d", *backendRef.Port)
+		initialErrorMessage := fmt.Sprintf("Unable to find service port for port %d", *backendRef.Port)
+		return nil, wrapError(errors.Errorf("%s", generateInvalidMessageWithRouteDetails(initialErrorMessage, routeKind, routeIdentifier)), gwv1.GatewayReasonListenersNotValid, gwv1.RouteReasonBackendNotFound)
 	}
 
 	// Weight specifies the proportion of requests forwarded to the referenced
diff --git a/pkg/gateway/routeutils/backend_test.go b/pkg/gateway/routeutils/backend_test.go
index 1ec9b4f4f8..d870819ce6 100644
--- a/pkg/gateway/routeutils/backend_test.go
+++ b/pkg/gateway/routeutils/backend_test.go
@@ -283,7 +283,7 @@ func TestCommonBackendLoader(t *testing.T) {
 					Port:      portConverter(80),
 				},
 			},
-			expectNoResult: true,
+			expectErr: true,
 		},
 		{
 			name: "missing port in backend ref should result in an error",
diff --git a/pkg/gateway/routeutils/grpc.go b/pkg/gateway/routeutils/grpc.go
index 8a1586d76a..83736ee7f8 100644
--- a/pkg/gateway/routeutils/grpc.go
+++ b/pkg/gateway/routeutils/grpc.go
@@ -128,5 +128,5 @@ func ListGRPCRoutes(context context.Context, k8sClient client.Client) ([]preLoad
 		result = append(result, convertGRPCRoute(item))
 	}
 
-	return result, err
+	return result, nil
 }
diff --git a/pkg/gateway/routeutils/http.go b/pkg/gateway/routeutils/http.go
index a5b2b9660b..b2e137ab9d 100644
--- a/pkg/gateway/routeutils/http.go
+++ b/pkg/gateway/routeutils/http.go
@@ -128,5 +128,5 @@ func ListHTTPRoutes(context context.Context, k8sClient client.Client) ([]preLoad
 		result = append(result, convertHTTPRoute(item))
 	}
 
-	return result, err
+	return result, nil
 }
diff --git a/pkg/gateway/routeutils/listener_attachment_helper.go b/pkg/gateway/routeutils/listener_attachment_helper.go
index fd1de8bdac..4bb55d98e3 100644
--- a/pkg/gateway/routeutils/listener_attachment_helper.go
+++ b/pkg/gateway/routeutils/listener_attachment_helper.go
@@ -2,7 +2,9 @@ package routeutils
 
 import (
 	"context"
+	"fmt"
 	"github.com/go-logr/logr"
+	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
@@ -145,8 +147,10 @@ func (attachmentHelper *listenerAttachmentHelperImpl) hostnameCheck(listener gwv
 	isListenerHostnameValid, err := IsHostNameInValidFormat(string(*listener.Hostname))
 	if err != nil {
 		attachmentHelper.logger.Error(err, "listener hostname is not valid", "listener", listener.Name, "hostname", *listener.Hostname)
-		return false, err
+		initialErrorMessage := fmt.Sprintf("listener hostname %s is not valid (listener name %s)", listener.Name, *listener.Hostname)
+		return false, wrapError(errors.Errorf("%s", initialErrorMessage), gwv1.GatewayReasonListenersNotValid, gwv1.RouteReasonUnsupportedValue)
 	}
+
 	if !isListenerHostnameValid {
 		return false, nil
 	}
diff --git a/pkg/gateway/routeutils/loader_error.go b/pkg/gateway/routeutils/loader_error.go
new file mode 100644
index 0000000000..86c2713010
--- /dev/null
+++ b/pkg/gateway/routeutils/loader_error.go
@@ -0,0 +1,42 @@
+package routeutils
+
+import (
+	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
+)
+
+type LoaderError interface {
+	Error() string
+	GetRawError() error
+	GetGatewayReason() gwv1.GatewayConditionReason
+	GetRouteReason() gwv1.RouteConditionReason
+}
+
+type loaderErrorImpl struct {
+	resolvedGatewayCondition gwv1.GatewayConditionReason
+	resolvedRouteCondition   gwv1.RouteConditionReason
+	underlyingErr            error
+}
+
+func wrapError(underlyingErr error, gatewayCondition gwv1.GatewayConditionReason, routeCondition gwv1.RouteConditionReason) LoaderError {
+	return &loaderErrorImpl{
+		underlyingErr:            underlyingErr,
+		resolvedGatewayCondition: gatewayCondition,
+		resolvedRouteCondition:   routeCondition,
+	}
+}
+
+func (e *loaderErrorImpl) GetRawError() error {
+	return e.underlyingErr
+}
+
+func (e *loaderErrorImpl) GetGatewayReason() gwv1.GatewayConditionReason {
+	return e.resolvedGatewayCondition
+}
+
+func (e *loaderErrorImpl) GetRouteReason() gwv1.RouteConditionReason {
+	return e.resolvedRouteCondition
+}
+
+func (e *loaderErrorImpl) Error() string {
+	return e.underlyingErr.Error()
+}
diff --git a/pkg/gateway/routeutils/namespace_selector.go b/pkg/gateway/routeutils/namespace_selector.go
index c54f1aeacb..6cbc226502 100644
--- a/pkg/gateway/routeutils/namespace_selector.go
+++ b/pkg/gateway/routeutils/namespace_selector.go
@@ -2,10 +2,12 @@ package routeutils
 
 import (
 	"context"
+	"github.com/pkg/errors"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
 )
 
 // namespaceSelector is an internal utility
@@ -33,7 +35,7 @@ func (n *namespaceSelectorImpl) getNamespacesFromSelector(context context.Contex
 
 	convertedSelector, err := metav1.LabelSelectorAsSelector(selector)
 	if err != nil {
-		return nil, err
+		return nil, wrapError(errors.Wrapf(err, "Unable to parse selector %s", selector), gwv1.GatewayReasonListenersNotValid, gwv1.RouteReasonUnsupportedValue)
 	}
 
 	err = n.k8sClient.List(context, &namespaceList, client.MatchingLabelsSelector{Selector: convertedSelector})
diff --git a/pkg/gateway/routeutils/route_listener_mapper.go b/pkg/gateway/routeutils/route_listener_mapper.go
index 84adaebfb5..df423d3091 100644
--- a/pkg/gateway/routeutils/route_listener_mapper.go
+++ b/pkg/gateway/routeutils/route_listener_mapper.go
@@ -8,7 +8,7 @@ import (
 )
 
 // listenerToRouteMapper is an internal utility that will map a list of routes to the listeners of a gateway
-// if the gateway and/or route are incompatible, then route is discarded.
+// if the gateway and/or route are incompatible, then the route is discarded.
 type listenerToRouteMapper interface {
 	mapGatewayAndRoutes(context context.Context, gw gwv1.Gateway, routes []preLoadRouteDescriptor, deferredRouteReconciler RouteReconciler) (map[int][]preLoadRouteDescriptor, error)
 }
diff --git a/pkg/gateway/routeutils/tcp.go b/pkg/gateway/routeutils/tcp.go
index a34e79d468..ec3a6984bd 100644
--- a/pkg/gateway/routeutils/tcp.go
+++ b/pkg/gateway/routeutils/tcp.go
@@ -128,5 +128,5 @@ func ListTCPRoutes(context context.Context, k8sClient client.Client) ([]preLoadR
 	for _, item := range routeList.Items {
 		result = append(result, convertTCPRoute(item))
 	}
-	return result, err
+	return result, nil
 }
diff --git a/pkg/gateway/routeutils/tls.go b/pkg/gateway/routeutils/tls.go
index 911b18dfdf..fde47b24e6 100644
--- a/pkg/gateway/routeutils/tls.go
+++ b/pkg/gateway/routeutils/tls.go
@@ -127,5 +127,5 @@ func ListTLSRoutes(context context.Context, k8sClient client.Client) ([]preLoadR
 		result = append(result, convertTLSRoute(item))
 	}
 
-	return result, err
+	return result, nil
 }
diff --git a/pkg/gateway/routeutils/udp.go b/pkg/gateway/routeutils/udp.go
index fca6c9d124..3662015b20 100644
--- a/pkg/gateway/routeutils/udp.go
+++ b/pkg/gateway/routeutils/udp.go
@@ -126,5 +126,5 @@ func ListUDPRoutes(context context.Context, k8sClient client.Client) ([]preLoadR
 		result = append(result, convertUDPRoute(item))
 	}
 
-	return result, err
+	return result, nil
 }
diff --git a/pkg/gateway/routeutils/utils.go b/pkg/gateway/routeutils/utils.go
index 30dd2e22e3..537173b043 100644
--- a/pkg/gateway/routeutils/utils.go
+++ b/pkg/gateway/routeutils/utils.go
@@ -3,6 +3,7 @@ package routeutils
 import (
 	"context"
 	"fmt"
+	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"net"
@@ -13,24 +14,24 @@ import (
 // ListL4Routes retrieves all Layer 4 routes (TCP, UDP, TLS) from the cluster.
 func ListL4Routes(ctx context.Context, k8sClient client.Client) ([]preLoadRouteDescriptor, error) {
 	l4Routes := make([]preLoadRouteDescriptor, 0)
-	var routekinds []RouteKind
+	var failedRoutes []RouteKind
 	tcpRoutes, err := ListTCPRoutes(ctx, k8sClient)
 	if err != nil {
-		routekinds = append(routekinds, TCPRouteKind)
+		failedRoutes = append(failedRoutes, TCPRouteKind)
 	}
 	l4Routes = append(l4Routes, tcpRoutes...)
 	udpRoutes, err := ListUDPRoutes(ctx, k8sClient)
 	if err != nil {
-		routekinds = append(routekinds, UDPRouteKind)
+		failedRoutes = append(failedRoutes, UDPRouteKind)
 	}
 	l4Routes = append(l4Routes, udpRoutes...)
 	tlsRoutes, err := ListTLSRoutes(ctx, k8sClient)
 	if err != nil {
-		routekinds = append(routekinds, TLSRouteKind)
+		failedRoutes = append(failedRoutes, TLSRouteKind)
 	}
 	l4Routes = append(l4Routes, tlsRoutes...)
-	if len(routekinds) > 0 {
-		err = fmt.Errorf("failed to list L4 routes, %s", routekinds)
+	if len(failedRoutes) > 0 {
+		err = errors.Errorf("failed to list L4 routes, %s", failedRoutes)
 	}
 	return l4Routes, err
 }
@@ -38,19 +39,19 @@ func ListL4Routes(ctx context.Context, k8sClient client.Client) ([]preLoadRouteD
 // ListL7Routes retrieves all Layer 7 routes (HTTP, gRPC) from the cluster.
 func ListL7Routes(ctx context.Context, k8sClient client.Client) ([]preLoadRouteDescriptor, error) {
 	l7Routes := make([]preLoadRouteDescriptor, 0)
-	var routekinds []RouteKind
+	var failedRoutes []RouteKind
 	httpRoutes, err := ListHTTPRoutes(ctx, k8sClient)
 	if err != nil {
-		routekinds = append(routekinds, HTTPRouteKind)
+		failedRoutes = append(failedRoutes, HTTPRouteKind)
 	}
 	l7Routes = append(l7Routes, httpRoutes...)
 	grpcRoutes, err := ListGRPCRoutes(ctx, k8sClient)
 	if err != nil {
-		routekinds = append(routekinds, GRPCRouteKind)
+		failedRoutes = append(failedRoutes, GRPCRouteKind)
 	}
 	l7Routes = append(l7Routes, grpcRoutes...)
-	if len(routekinds) > 0 {
-		err = fmt.Errorf("failed to list L7 routes, %s", routekinds)
+	if len(failedRoutes) > 0 {
+		err = errors.Errorf("failed to list L7 routes, %s", failedRoutes)
 	}
 	return l7Routes, err
 }
@@ -160,3 +161,7 @@ func GetHostnamePrecedenceOrder(hostnameOne, hostnameTwo string) int {
 		}
 	}
 }
+
+func generateInvalidMessageWithRouteDetails(initialMessage string, routeKind RouteKind, routeIdentifier types.NamespacedName) string {
+	return fmt.Sprintf("%s. Invalid data can be found in route (%s, %s:%s)", initialMessage, routeKind, routeIdentifier.Namespace, routeIdentifier.Name)
+}
diff --git a/pkg/gateway/routeutils/utils_test.go b/pkg/gateway/routeutils/utils_test.go
index e17de4b0ad..49504bd2fb 100644
--- a/pkg/gateway/routeutils/utils_test.go
+++ b/pkg/gateway/routeutils/utils_test.go
@@ -163,7 +163,6 @@ func Test_ListL4Routes(t *testing.T) {
 				return k8sClient
 			},
 			expectedRoutes: 3,
-			expectedErr:    nil,
 		},
 		{
 			name: "Handles error in TCP routes",
@@ -188,7 +187,11 @@ func Test_ListL4Routes(t *testing.T) {
 			client := tt.mockSetup(ctrl)
 			routes, err := ListL4Routes(context.Background(), client)
 
-			assert.Equal(t, err, tt.expectedErr)
+			if tt.expectedErr == nil {
+				assert.NoError(t, err)
+			} else {
+				assert.Equal(t, tt.expectedErr.Error(), err.Error())
+			}
 			assert.Len(t, routes, tt.expectedRoutes)
 
 		})
@@ -293,7 +296,11 @@ func Test_ListL7Routes(t *testing.T) {
 			client := tt.mockSetup(ctrl)
 			routes, err := ListL7Routes(context.Background(), client)
 
-			assert.Equal(t, err, tt.expectedErr)
+			if tt.expectedErr == nil {
+				assert.NoError(t, err)
+			} else {
+				assert.Equal(t, tt.expectedErr.Error(), err.Error())
+			}
 			assert.Len(t, routes, tt.expectedRoutes)
 
 		})
diff --git a/pkg/model/elbv2/load_balancer.go b/pkg/model/elbv2/load_balancer.go
index 94cbc3f3e4..35f97c11a5 100644
--- a/pkg/model/elbv2/load_balancer.go
+++ b/pkg/model/elbv2/load_balancer.go
@@ -2,6 +2,7 @@ package elbv2
 
 import (
 	"context"
+	elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
 	"github.com/pkg/errors"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
 )
@@ -212,4 +213,7 @@ type LoadBalancerStatus struct {
 
 	// The public DNS name of the load balancer.
 	DNSName string `json:"dnsName"`
+
+	// The current state of the load balancer (active, provisioning, etc)
+	ProvisioningState *elbv2types.LoadBalancerState `json:"provisioningState"`
 }
diff --git a/pkg/testutils/client_test_utils.go b/pkg/testutils/client_test_utils.go
index 6ced1c3f71..da390aef85 100644
--- a/pkg/testutils/client_test_utils.go
+++ b/pkg/testutils/client_test_utils.go
@@ -52,5 +52,5 @@ func GenerateTestClient() client.Client {
 	elbv2gw.AddToScheme(k8sSchema)
 	gwbeta1.AddToScheme(k8sSchema)
 
-	return testclient.NewClientBuilder().WithScheme(k8sSchema).Build()
+	return testclient.NewClientBuilder().WithStatusSubresource(&gwv1.GatewayClass{}).WithStatusSubresource(&gwv1.Gateway{}).WithScheme(k8sSchema).Build()
 }